Skip to content

Commit

Permalink
Merge pull request dotnet#3 from dsyme/statics-in-interfaces-2
Browse files Browse the repository at this point in the history
  • Loading branch information
vzarytovskii authored Jun 27, 2022
2 parents 6122923 + b512c93 commit d4504db
Show file tree
Hide file tree
Showing 16 changed files with 195 additions and 85 deletions.
123 changes: 77 additions & 46 deletions src/Compiler/Checking/CheckExpressions.fs

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions src/Compiler/Checking/ConstraintSolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2494,12 +2494,11 @@ and CanMemberSigsMatchUpToCheck
assignedItemSetters |> MapCombineTDCD (fun (AssignedItemSetter(_, item, caller)) ->
let name, calledArgTy =
match item with
| AssignedPropSetter(_, pminfo, pminst) ->
| AssignedPropSetter(_, _, pminfo, pminst) ->
let calledArgTy = List.head (List.head (pminfo.GetParamTypes(amap, m, pminst)))
pminfo.LogicalName, calledArgTy

| AssignedILFieldSetter(finfo) ->
(* Get or set instance IL field *)
let calledArgTy = finfo.FieldType(amap, m)
finfo.FieldName, calledArgTy

Expand Down
54 changes: 31 additions & 23 deletions src/Compiler/Checking/MethodCalls.fs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ type AssignedCalledArg<'T> =

/// Represents the possibilities for a named-setter argument (a property, field, or a record field setter)
type AssignedItemSetterTarget =
| AssignedPropSetter of PropInfo * MethInfo * TypeInst (* the MethInfo is a non-indexer setter property *)
// the MethInfo is a non-indexer setter property
| AssignedPropSetter of staticTyOpt: TType option * pinfo: PropInfo * minfo: MethInfo * pminst: TypeInst
| AssignedILFieldSetter of ILFieldInfo
| AssignedRecdFieldSetter of RecdFieldInfo

Expand Down Expand Up @@ -197,11 +198,13 @@ let TryFindRelevantImplicitConversion (infoReader: InfoReader) ad reqdTy actualT
isTyparTy g actualTy && (let ftyvs = freeInType CollectAll reqdTy2 in ftyvs.FreeTypars.Contains(destTyparTy g actualTy))) then

let implicits =
infoReader.FindImplicitConversions m ad actualTy @
infoReader.FindImplicitConversions m ad reqdTy2
[ for conv in infoReader.FindImplicitConversions m ad actualTy do
(conv, actualTy)
for conv in infoReader.FindImplicitConversions m ad reqdTy2 do
(conv, reqdTy2) ]

let implicits =
implicits |> List.filter (fun minfo ->
implicits |> List.filter (fun (minfo, _staticTy) ->
not minfo.IsInstance &&
minfo.FormalMethodTyparInst.IsEmpty &&
(match minfo.GetParamTypes(amap, m, []) with
Expand All @@ -212,12 +215,12 @@ let TryFindRelevantImplicitConversion (infoReader: InfoReader) ad reqdTy actualT
)

match implicits with
| [minfo] ->
Some (minfo, (reqdTy, reqdTy2, ignore))
| minfo :: _ ->
Some (minfo, (reqdTy, reqdTy2, fun denv ->
| [(minfo, staticTy) ] ->
Some (minfo, staticTy, (reqdTy, reqdTy2, ignore))
| (minfo, staticTy) :: _ ->
Some (minfo, staticTy, (reqdTy, reqdTy2, fun denv ->
let reqdTy2Text, actualTyText, _cxs = NicePrint.minimalStringsOfTwoTypes denv reqdTy2 actualTy
let implicitsText = NicePrint.multiLineStringOfMethInfos infoReader m denv implicits
let implicitsText = NicePrint.multiLineStringOfMethInfos infoReader m denv (List.map fst implicits)
errorR(Error(FSComp.SR.tcAmbiguousImplicitConversion(actualTyText, reqdTy2Text, implicitsText), m))))
| _ -> None
else
Expand Down Expand Up @@ -289,7 +292,7 @@ let rec AdjustRequiredTypeForTypeDirectedConversions (infoReader: InfoReader) ad
// eliminate articifical constrained type variables.
elif g.langVersion.SupportsFeature LanguageFeature.AdditionalTypeDirectedConversions then
match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with
| Some (minfo, eqn) -> actualTy, TypeDirectedConversionUsed.Yes(warn (TypeDirectedConversion.Implicit minfo)), Some eqn
| Some (minfo, _staticTy, eqn) -> actualTy, TypeDirectedConversionUsed.Yes(warn (TypeDirectedConversion.Implicit minfo)), Some eqn
| None -> reqdTy, TypeDirectedConversionUsed.No, None

else reqdTy, TypeDirectedConversionUsed.No, None
Expand Down Expand Up @@ -617,7 +620,8 @@ type CalledMeth<'T>
| [pinfo] when pinfo.HasSetter && not pinfo.IsIndexer ->
let pminfo = pinfo.SetterMethod
let pminst = freshenMethInfo m pminfo
Choice1Of2(AssignedItemSetter(id, AssignedPropSetter(pinfo, pminfo, pminst), e))
let propStaticTyOpt = if isTyparTy g returnedObjTy then Some returnedObjTy else None
Choice1Of2(AssignedItemSetter(id, AssignedPropSetter(propStaticTyOpt, pinfo, pminfo, pminst), e))
| _ ->
let epinfos =
match nameEnv with
Expand All @@ -636,7 +640,8 @@ type CalledMeth<'T>
| Some(TType_app(_, types, _)) -> types
| _ -> pminst

Choice1Of2(AssignedItemSetter(id, AssignedPropSetter(pinfo, pminfo, pminst), e))
let propStaticTyOpt = if isTyparTy g returnedObjTy then Some returnedObjTy else None
Choice1Of2(AssignedItemSetter(id, AssignedPropSetter(propStaticTyOpt, pinfo, pminfo, pminst), e))
| _ ->
match infoReader.GetILFieldInfosOfType(Some(nm), ad, m, returnedObjTy) with
| finfo :: _ ->
Expand Down Expand Up @@ -869,9 +874,11 @@ let IsBaseCall objArgs =
/// Compute whether we insert a 'coerce' on the 'this' pointer for an object model call
/// For example, when calling an interface method on a struct, or a method on a constrained
/// variable type.
let ComputeConstrainedCallInfo g amap m (objArgs, minfo: MethInfo) =
match objArgs with
| [objArgExpr] when not minfo.IsExtensionMember ->
let ComputeConstrainedCallInfo g amap m staticTyOpt objArgs (minfo: MethInfo) =
match objArgs, staticTyOpt with
| [], Some staticTy when not minfo.IsExtensionMember && not minfo.IsInstance && minfo.IsAbstract -> Some staticTy

| [objArgExpr], _ when not minfo.IsExtensionMember ->
let methObjTy = minfo.ApparentEnclosingType
let objArgTy = tyOfExpr g objArgExpr
if TypeDefinitelySubsumesTypeNoCoercion 0 g amap m methObjTy objArgTy
Expand All @@ -891,8 +898,8 @@ let ComputeConstrainedCallInfo g amap m (objArgs, minfo: MethInfo) =

/// Adjust the 'this' pointer before making a call
/// Take the address of a struct, and coerce to an interface/base/constraint type if necessary
let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m objArgs f =
let ccallInfo = ComputeConstrainedCallInfo g amap m (objArgs, minfo)
let TakeObjAddrForMethodCall g amap (minfo: MethInfo) isMutable m staticTyOpt objArgs f =
let ccallInfo = ComputeConstrainedCallInfo g amap m staticTyOpt objArgs minfo

let wrap, objArgs =

Expand Down Expand Up @@ -1070,10 +1077,10 @@ let TryImportProvidedMethodBaseAsLibraryIntrinsic (amap: Import.ImportMap, m: ra
// minst: the instantiation to apply for a generic method
// objArgs: the 'this' argument, if any
// args: the arguments, if any
let BuildMethodCall tcVal g amap isMutable m isProp minfo valUseFlags minst objArgs args =
let BuildMethodCall tcVal g amap isMutable m isProp minfo valUseFlags minst objArgs args staticTyOpt =
let direct = IsBaseCall objArgs

TakeObjAddrForMethodCall g amap minfo isMutable m objArgs (fun ccallInfo objArgs ->
TakeObjAddrForMethodCall g amap minfo isMutable m staticTyOpt objArgs (fun ccallInfo objArgs ->
let allArgs = objArgs @ args
let valUseFlags =
if direct && (match valUseFlags with NormalValUse -> true | _ -> false) then
Expand Down Expand Up @@ -1288,9 +1295,10 @@ let rec AdjustExprForTypeDirectedConversions tcVal (g: TcGlobals) amap infoReade

else
match TryFindRelevantImplicitConversion infoReader ad reqdTy actualTy m with
| Some (minfo, _) ->
| Some (minfo, staticTy, _) ->
MethInfoChecks g amap false None [] ad m minfo
let callExpr, _ = BuildMethodCall tcVal g amap Mutates.NeverMutates m false minfo ValUseFlag.NormalValUse [] [] [expr]
let staticTyOpt = if isTyparTy g staticTy then Some staticTy else None
let callExpr, _ = BuildMethodCall tcVal g amap Mutates.NeverMutates m false minfo ValUseFlag.NormalValUse [] [] [expr] staticTyOpt
assert (let resTy = tyOfExpr g callExpr in typeEquiv g reqdTy resTy)
callExpr
| None -> mkCoerceIfNeeded g reqdTy actualTy expr
Expand Down Expand Up @@ -1949,7 +1957,7 @@ module ProvidedMethodCalls =
let targetMethInfo = ProvidedMeth(amap, ctor.PApply((fun ne -> upcast ne), m), None, m)
let objArgs = []
let arguments = [ for ea in args.PApplyArray(id, "GetInvokerExpression", m) -> exprToExpr ea ]
let callExpr = BuildMethodCall tcVal g amap Mutates.PossiblyMutates m false targetMethInfo isSuperInit [] objArgs arguments
let callExpr = BuildMethodCall tcVal g amap Mutates.PossiblyMutates m false targetMethInfo isSuperInit [] objArgs arguments None
callExpr

and addVar (v: Tainted<ProvidedVar>) =
Expand Down Expand Up @@ -1984,7 +1992,7 @@ module ProvidedMethodCalls =
let mut = if top then mut else PossiblyMutates
let isSuperInit = if top then isSuperInit else ValUseFlag.NormalValUse
let isProp = if top then isProp else false
let callExpr = BuildMethodCall tcVal g amap mut m isProp targetMethInfo isSuperInit replacementGenericArguments objArgs arguments
let callExpr = BuildMethodCall tcVal g amap mut m isProp targetMethInfo isSuperInit replacementGenericArguments objArgs arguments None
Some meth, callExpr

and varToExpr (pe: Tainted<ProvidedVar>) =
Expand Down
4 changes: 3 additions & 1 deletion src/Compiler/Checking/MethodCalls.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ type AssignedCalledArg<'T> =

/// Represents the possibilities for a named-setter argument (a property, field, or a record field setter)
type AssignedItemSetterTarget =
| AssignedPropSetter of PropInfo * MethInfo * TypeInst
| AssignedPropSetter of staticTyOpt: TType option * pinfo: PropInfo * minfo: MethInfo * pminst: TypeInst
| AssignedILFieldSetter of ILFieldInfo
| AssignedRecdFieldSetter of RecdFieldInfo

Expand Down Expand Up @@ -348,6 +348,7 @@ val MakeMethInfoCall: amap: ImportMap -> m: range -> minfo: MethInfo -> minst: T
// minst: the instantiation to apply for a generic method
// objArgs: the 'this' argument, if any
// args: the arguments, if any
// staticTyOpt: the static type that governs the call, different to the nominal type containing the member, e.g. 'T.CallSomeMethod()
val BuildMethodCall:
tcVal: (ValRef -> ValUseFlag -> TType list -> range -> Expr * TType) ->
g: TcGlobals ->
Expand All @@ -360,6 +361,7 @@ val BuildMethodCall:
minst: TType list ->
objArgs: Expr list ->
args: Expr list ->
staticTyOpt: TType option ->
Expr * TType

/// Build a call to the System.Object constructor taking no arguments,
Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Checking/MethodOverrides.fs
Original file line number Diff line number Diff line change
Expand Up @@ -923,9 +923,9 @@ let FinalTypeDefinitionChecksAtEndOfInferenceScope (infoReader: InfoReader, nenv
/// at the member signature prior to type inference. This is used to pre-assign type information if it does
let GetAbstractMethInfosForSynMethodDecl(infoReader: InfoReader, ad, memberName: Ident, bindm, typToSearchForAbstractMembers, valSynData, memberFlags: SynMemberFlags) =

if not memberFlags.IsInstance && memberFlags.IsOverrideOrExplicitImpl then
checkLanguageFeatureRuntimeAndRecover infoReader LanguageFeature.InterfacesWithAbstractStaticMembers bindm
checkLanguageFeatureAndRecover infoReader.g.langVersion LanguageFeature.InterfacesWithAbstractStaticMembers bindm
//if not memberFlags.IsInstance && memberFlags.IsOverrideOrExplicitImpl then
// checkLanguageFeatureRuntimeAndRecover infoReader LanguageFeature.InterfacesWithAbstractStaticMembers bindm
// checkLanguageFeatureAndRecover infoReader.g.langVersion LanguageFeature.InterfacesWithAbstractStaticMembers bindm

let minfos =
match typToSearchForAbstractMembers with
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Checking/PatternMatchCompilation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1065,11 +1065,11 @@ let CompilePatternBasic
| Some (ediCaptureMethInfo, ediThrowMethInfo) ->
let edi, _ =
BuildMethodCall tcVal g amap NeverMutates mMatch false
ediCaptureMethInfo ValUseFlag.NormalValUse [] [] [ (exprForVal mMatch origInputVal) ]
ediCaptureMethInfo ValUseFlag.NormalValUse [] [] [ (exprForVal mMatch origInputVal) ] None

let e, _ =
BuildMethodCall tcVal g amap NeverMutates mMatch false
ediThrowMethInfo ValUseFlag.NormalValUse [] [edi] [ ]
ediThrowMethInfo ValUseFlag.NormalValUse [] [edi] [ ] None

mkCompGenSequential mMatch e (mkDefault (mMatch, resultTy))

Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/TypeHierarchy.fs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ type AllowMultiIntfInstantiations = Yes | No

/// Traverse the type hierarchy, e.g. f D (f C (f System.Object acc)).
/// Visit base types and interfaces first.
let private FoldHierarchyOfTypeAux followInterfaces allowMultiIntfInst skipUnref visitor g amap m ty acc =
let FoldHierarchyOfTypeAux followInterfaces allowMultiIntfInst skipUnref visitor g amap m ty acc =
let rec loop ndeep ty (visitedTycon, visited: TyconRefMultiMap<_>, acc as state) =

let seenThisTycon =
Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Optimize/LowerComputedCollections.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ let BuildDisposableCleanup tcVal (g: TcGlobals) infoReader m (v: Val) =
assert (TypeFeasiblySubsumesType 0 g infoReader.amap m g.system_IDisposable_ty CanCoerce v.Type)
// We can use NeverMutates here because the variable is going out of scope, there is no need to take a defensive
// copy of it.
let disposeExpr, _ = BuildMethodCall tcVal g infoReader.amap NeverMutates m false disposeMethod NormalValUse [] [exprForVal v.Range v] []
let disposeExpr, _ = BuildMethodCall tcVal g infoReader.amap NeverMutates m false disposeMethod NormalValUse [] [exprForVal v.Range v] [] None
//callNonOverloadedILMethod g infoReader.amap m "Dispose" g.system_IDisposable_ty [exprForVal v.Range v]

disposeExpr
else
let disposeObjVar, disposeObjExpr = mkCompGenLocal m "objectToDispose" g.system_IDisposable_ty
let disposeExpr, _ = BuildMethodCall tcVal g infoReader.amap PossiblyMutates m false disposeMethod NormalValUse [] [disposeObjExpr] []
let disposeExpr, _ = BuildMethodCall tcVal g infoReader.amap PossiblyMutates m false disposeMethod NormalValUse [] [disposeObjExpr] [] None
let inputExpr = mkCoerceExpr(exprForVal v.Range v, g.obj_ty, m, v.Type)
mkIsInstConditional g m g.system_IDisposable_ty inputExpr disposeObjVar disposeExpr (mkUnit g m)

Expand All @@ -44,7 +44,7 @@ let mkCallCollectorMethod tcVal (g: TcGlobals) infoReader m name collExpr args =
match GetIntrinsicMethInfosOfType infoReader (Some name) AccessibleFromSomewhere AllowMultiIntfInstantiations.Yes IgnoreOverrides m listCollectorTy with
| [x] -> x
| _ -> error(InternalError("no " + name + " method found on Collector", m))
let expr, _ = BuildMethodCall tcVal g infoReader.amap DefinitelyMutates m false addMethod NormalValUse [] [collExpr] args
let expr, _ = BuildMethodCall tcVal g infoReader.amap DefinitelyMutates m false addMethod NormalValUse [] [collExpr] args None
expr

let mkCallCollectorAdd tcVal (g: TcGlobals) infoReader m collExpr arg =
Expand Down
1 change: 1 addition & 0 deletions src/Compiler/Service/FSharpParseFileResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ type FSharpParseFileResults(diagnostics: FSharpDiagnostic[], input: ParsedInput,
| SynExpr.LibraryOnlyILAssembly _
| SynExpr.LibraryOnlyStaticOptimization _
| SynExpr.Null _
| SynExpr.TyparDotIdent _
| SynExpr.Ident _
| SynExpr.ImplicitZero _
| SynExpr.Const _
Expand Down
2 changes: 2 additions & 0 deletions src/Compiler/Service/ServiceParseTreeWalk.fs
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,8 @@ module SyntaxTraversal =

| SynExpr.LongIdent (_, _longIdent, _altNameRefCell, _range) -> None

| SynExpr.TyparDotIdent (_typar, _ident, _range) -> None

| SynExpr.LongIdentSet (_longIdent, synExpr, _range) -> traverseSynExpr synExpr

| SynExpr.DotGet (synExpr, _dotm, _longIdent, _range) -> traverseSynExpr synExpr
Expand Down
28 changes: 24 additions & 4 deletions src/Compiler/SyntaxTree/LexFilter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,11 @@ type LexFilterImpl (
let peekAdjacentTypars indentation (tokenTup: TokenTup) =
let lookaheadTokenTup = peekNextTokenTup()
match lookaheadTokenTup.Token with
| INFIX_COMPARE_OP "</" | LESS _ ->
| INFIX_COMPARE_OP "</"
| INFIX_COMPARE_OP "<^"
// NOTE: this is "<@"
| LQUOTE ("<@ @>", false)
| LESS _ ->
let tokenEndPos = tokenTup.LexbufState.EndPos
if isAdjacent tokenTup lookaheadTokenTup then
let mutable stack = []
Expand Down Expand Up @@ -1070,7 +1074,14 @@ type LexFilterImpl (
let dotTokenTup = peekNextTokenTup()
stack <- (pool.UseLocation(dotTokenTup, HIGH_PRECEDENCE_PAREN_APP), false) :: stack
true
| LPAREN | LESS _ | LBRACK | LBRACK_LESS | INFIX_COMPARE_OP "</" ->
| LPAREN
| LESS _
| LBRACK
| LBRACK_LESS
| INFIX_COMPARE_OP "</"
| INFIX_COMPARE_OP "<^"
// NOTE: this is "<@"
| LQUOTE ("<@ @>", false) ->
scanAhead (nParen+1)

// These tokens CAN occur in non-parenthesized positions in the grammar of types or type parameter definitions
Expand Down Expand Up @@ -1119,13 +1130,22 @@ type LexFilterImpl (

let res = scanAhead 0
// Put the tokens back on and smash them up if needed
stack |> List.iter (fun (tokenTup, smash) ->
for (tokenTup, smash) in stack do
if smash then
match tokenTup.Token with
| INFIX_COMPARE_OP "</" ->
delayToken (pool.UseShiftedLocation(tokenTup, INFIX_STAR_DIV_MOD_OP "/", 1, 0))
delayToken (pool.UseShiftedLocation(tokenTup, LESS res, 0, -1))
pool.Return tokenTup
| INFIX_COMPARE_OP "<^" ->
delayToken (pool.UseShiftedLocation(tokenTup, INFIX_AT_HAT_OP "^", 1, 0))
delayToken (pool.UseShiftedLocation(tokenTup, LESS res, 0, -1))
pool.Return tokenTup
// NOTE: this is "<@"
| LQUOTE ("<@ @>", false) ->
delayToken (pool.UseShiftedLocation(tokenTup, INFIX_AT_HAT_OP "@", 1, 0))
delayToken (pool.UseShiftedLocation(tokenTup, LESS res, 0, -1))
pool.Return tokenTup
| GREATER_BAR_RBRACK ->
delayToken (pool.UseShiftedLocation(tokenTup, BAR_RBRACK, 1, 0))
delayToken (pool.UseShiftedLocation(tokenTup, GREATER res, 0, -2))
Expand All @@ -1146,7 +1166,7 @@ type LexFilterImpl (
pool.Return tokenTup
| _ -> delayToken tokenTup
else
delayToken tokenTup)
delayToken tokenTup
res
else
false
Expand Down
Loading

0 comments on commit d4504db

Please sign in to comment.