diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md index 65f52c982fa..72037533dfd 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md @@ -18,4 +18,4 @@ ### Changed -* Speed up unused opens handling for empty results. ([PR #16502](https://github.com/dotnet/fsharp/pull/16502)) \ No newline at end of file +* Speed up unused opens handling for empty results. ([PR #16502](https://github.com/dotnet/fsharp/pull/16502)) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md index ac442a61549..d153e616586 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.300.md @@ -5,6 +5,7 @@ ### Added * Parser recovers on complex primary constructor patterns, better tree representation for primary constructor patterns. ([PR #16425](https://github.com/dotnet/fsharp/pull/16425)) +* Name resolution: keep type vars in subsequent checks ([PR #16456](https://github.com/dotnet/fsharp/pull/16456)) ### Changed diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 6f9c0a21d53..5ff97971085 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -2941,7 +2941,7 @@ module EstablishTypeDefinitionCores = | Some (tc, args, m) -> let ad = envinner.AccessRights match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInType OpenQualified envinner.NameEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.Yes with - | Result (_, tcrefBeforeStaticArguments) when + | Result (_, tcrefBeforeStaticArguments, _) when tcrefBeforeStaticArguments.IsProvided && not tcrefBeforeStaticArguments.IsErased -> @@ -4117,11 +4117,11 @@ module TcDeclarations = | _ -> let resInfo = TypeNameResolutionStaticArgsInfo.FromTyArgs synTypars.Length - let _, tcref = + let tcref = match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.Binding OpenQualified envForDecls.NameEnv ad longPath resInfo PermitDirectReferenceToGeneratedType.No with | Result res -> // Update resolved type parameters with the names from the source. - let _, tcref = res + let _, tcref, _ = res if tcref.TyparsNoRange.Length = synTypars.Length then (tcref.TyparsNoRange, synTypars) ||> List.zip @@ -4131,11 +4131,12 @@ module TcDeclarations = typar.SetIdent(untypedIdent) ) - res - | res when inSig && List.isSingleton longPath -> - errorR(Deprecated(FSComp.SR.tcReservedSyntaxForAugmentation(), m)) - ForceRaise res - | res -> ForceRaise res + tcref + + | Exception exn -> + if inSig && List.isSingleton longPath then + errorR(Deprecated(FSComp.SR.tcReservedSyntaxForAugmentation(), m)) + ForceRaise (Exception exn) tcref let isInterfaceOrDelegateOrEnum = diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index f182c98ac85..e405ca29ae2 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -767,7 +767,7 @@ let TcConst (cenv: cenv) (overallTy: TType) m env synConst = | SynMeasure.One _ -> Measure.One | SynMeasure.Named(tc, m) -> let ad = env.eAccessRights - let _, tcref = ForceRaise(ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.Use OpenQualified env.eNameResEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No) + let _, tcref, _ = ForceRaise(ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.Use OpenQualified env.eNameResEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No) match tcref.TypeOrMeasureKind with | TyparKind.Type -> error(Error(FSComp.SR.tcExpectedUnitOfMeasureNotType(), m)) | TyparKind.Measure -> Measure.Const tcref @@ -4458,7 +4458,7 @@ and TcLongIdentType kindOpt (cenv: cenv) newOk checkConstraints occ iwsam env tp let m = synLongId.Range let ad = env.eAccessRights - let tinstEnclosing, tcref = ForceRaise(ResolveTypeLongIdent cenv.tcSink cenv.nameResolver occ OpenQualified env.NameEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No) + let tinstEnclosing, tcref, inst = ForceRaise(ResolveTypeLongIdent cenv.tcSink cenv.nameResolver occ OpenQualified env.NameEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No) CheckIWSAM cenv env checkConstraints iwsam m tcref @@ -4472,7 +4472,7 @@ and TcLongIdentType kindOpt (cenv: cenv) newOk checkConstraints occ iwsam env tp | _, TyparKind.Measure -> TType_measure (Measure.Const tcref), tpenv | _, TyparKind.Type -> - TcTypeApp cenv newOk checkConstraints occ env tpenv m tcref tinstEnclosing [] + TcTypeApp cenv newOk checkConstraints occ env tpenv m tcref tinstEnclosing [] inst /// Some.Long.TypeName /// ty1 SomeLongTypeName @@ -4480,7 +4480,7 @@ and TcLongIdentAppType kindOpt (cenv: cenv) newOk checkConstraints occ iwsam env let (SynLongIdent(tc, _, _)) = longId let ad = env.eAccessRights - let tinstEnclosing, tcref = + let tinstEnclosing, tcref, inst = let tyResInfo = TypeNameResolutionStaticArgsInfo.FromTyArgs args.Length ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInType OpenQualified env.eNameResEnv ad tc tyResInfo PermitDirectReferenceToGeneratedType.No |> ForceRaise @@ -4499,7 +4499,7 @@ and TcLongIdentAppType kindOpt (cenv: cenv) newOk checkConstraints occ iwsam env | _, TyparKind.Type -> if postfix && tcref.Typars m |> List.exists (fun tp -> match tp.Kind with TyparKind.Measure -> true | _ -> false) then error(Error(FSComp.SR.tcInvalidUnitsOfMeasurePrefix(), m)) - TcTypeApp cenv newOk checkConstraints occ env tpenv m tcref tinstEnclosing args + TcTypeApp cenv newOk checkConstraints occ env tpenv m tcref tinstEnclosing args inst | _, TyparKind.Measure -> match args, postfix with @@ -4518,8 +4518,8 @@ and TcNestedAppType (cenv: cenv) newOk checkConstraints occ iwsam env tpenv synL let leftTy, tpenv = TcType cenv newOk checkConstraints occ iwsam env tpenv synLeftTy match leftTy with | AppTy g (tcref, tinst) -> - let tcref = ResolveTypeLongIdentInTyconRef cenv.tcSink cenv.nameResolver env.eNameResEnv (TypeNameResolutionInfo.ResolveToTypeRefs (TypeNameResolutionStaticArgsInfo.FromTyArgs args.Length)) ad m tcref longId - TcTypeApp cenv newOk checkConstraints occ env tpenv m tcref tinst args + let tcref, inst = ResolveTypeLongIdentInTyconRef cenv.tcSink cenv.nameResolver env.eNameResEnv (TypeNameResolutionInfo.ResolveToTypeRefs (TypeNameResolutionStaticArgsInfo.FromTyArgs args.Length)) ad m tcref longId + TcTypeApp cenv newOk checkConstraints occ env tpenv m tcref tinst args inst | _ -> error(Error(FSComp.SR.tcTypeHasNoNestedTypes(), m)) @@ -4943,7 +4943,7 @@ and TcProvidedTypeApp (cenv: cenv) env tpenv tcref args m = /// Note that the generic type may be a nested generic type List.ListEnumerator. /// In this case, 'argsR is only the instantiation of the suffix type arguments, and pathTypeArgs gives /// the prefix of type arguments. -and TcTypeApp (cenv: cenv) newOk checkConstraints occ env tpenv m tcref pathTypeArgs (synArgTys: SynType list) = +and TcTypeApp (cenv: cenv) newOk checkConstraints occ env tpenv m tcref pathTypeArgs (synArgTys: SynType list) (tinst: TypeInst) = let g = cenv.g CheckTyconAccessible cenv.amap m env.AccessRights tcref |> ignore CheckEntityAttributes g tcref m |> CommitOperationResult @@ -4954,16 +4954,22 @@ and TcTypeApp (cenv: cenv) newOk checkConstraints occ env tpenv m tcref pathType if tcref.Deref.IsProvided then TcProvidedTypeApp cenv env tpenv tcref synArgTys m else #endif - let tps, _, tinst, _ = FreshenTyconRef2 g m tcref - - // If we're not checking constraints, i.e. when we first assert the super/interfaces of a type definition, then just - // clear the constraint lists of the freshly generated type variables. A little ugly but fairly localized. - if checkConstraints = NoCheckCxs then tps |> List.iter (fun tp -> tp.SetConstraints []) let synArgTysLength = synArgTys.Length let pathTypeArgsLength = pathTypeArgs.Length if tinst.Length <> pathTypeArgsLength + synArgTysLength then error (TyconBadArgs(env.DisplayEnv, tcref, pathTypeArgsLength + synArgTysLength, m)) + let tps = tinst |> List.skip pathTypeArgsLength |> List.map (fun t -> + match t with + | TType_var(typar, _) + | TType_measure(Measure.Var typar) -> typar + | t -> failwith $"TcTypeApp: {t}" + ) + + // If we're not checking constraints, i.e. when we first assert the super/interfaces of a type definition, then just + // clear the constraint lists of the freshly generated type variables. A little ugly but fairly localized. + if checkConstraints = NoCheckCxs then tps |> List.iter (fun tp -> tp.SetConstraints []) + let argTys, tpenv = // Get the suffix of typars let tpsForArgs = List.skip (tps.Length - synArgTysLength) tps @@ -5009,9 +5015,9 @@ and TcNestedTypeApplication (cenv: cenv) newOk checkConstraints occ iwsam env tp error(Error(FSComp.SR.tcTypeHasNoNestedTypes(), mWholeTypeApp)) match ty with - | TType_app(tcref, _, _) -> + | TType_app(tcref, inst, _) -> CheckIWSAM cenv env checkConstraints iwsam mWholeTypeApp tcref - TcTypeApp cenv newOk checkConstraints occ env tpenv mWholeTypeApp tcref pathTypeArgs tyargs + TcTypeApp cenv newOk checkConstraints occ env tpenv mWholeTypeApp tcref pathTypeArgs tyargs inst | _ -> error(InternalError("TcNestedTypeApplication: expected type application", mWholeTypeApp)) @@ -8163,10 +8169,10 @@ and TcNameOfExpr (cenv: cenv) env tpenv (synArg: SynExpr) = if (match delayed with [DelayedTypeApp _] | [] -> true | _ -> false) then let (TypeNameResolutionInfo(_, staticArgsInfo)) = GetLongIdentTypeNameInfo delayed match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInAttribute OpenQualified env.eNameResEnv ad longId staticArgsInfo PermitDirectReferenceToGeneratedType.No with - | Result (tinstEnclosing, tcref) when IsEntityAccessible cenv.amap m ad tcref -> + | Result (tinstEnclosing, tcref, inst) when IsEntityAccessible cenv.amap m ad tcref -> match delayed with | [DelayedTypeApp (tyargs, _, mExprAndTypeArgs)] -> - TcTypeApp cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv mExprAndTypeArgs tcref tinstEnclosing tyargs |> ignore + TcTypeApp cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv mExprAndTypeArgs tcref tinstEnclosing tyargs inst |> ignore | _ -> () true // resolved to a type name, done with checks | _ -> @@ -10858,7 +10864,7 @@ and TcAttributeEx canFail (cenv: cenv) (env: TcEnv) attrTgt attrEx (synAttr: Syn match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInAttribute OpenQualified env.eNameResEnv ad tycon TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No with | Exception err -> raze err - | Result(tinstEnclosing, tcref) -> success(TcTypeApp cenv NoNewTypars CheckCxs ItemOccurence.UseInAttribute env tpenv mAttr tcref tinstEnclosing []) + | Result(tinstEnclosing, tcref, inst) -> success(TcTypeApp cenv NoNewTypars CheckCxs ItemOccurence.UseInAttribute env tpenv mAttr tcref tinstEnclosing [] inst) ForceRaise ((try1 (tyid.idText + "Attribute")) |> otherwise (fun () -> (try1 tyid.idText))) diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index c30ca0cdc66..2667ea6ccfc 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -57,97 +57,18 @@ open FSharp.Compiler.Import open FSharp.Compiler.InfoReader open FSharp.Compiler.Infos open FSharp.Compiler.MethodCalls +open FSharp.Compiler.NameResolution open FSharp.Compiler.Syntax open FSharp.Compiler.Syntax.PrettyNaming open FSharp.Compiler.SyntaxTreeOps open FSharp.Compiler.TcGlobals open FSharp.Compiler.Text -open FSharp.Compiler.Text.Range open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeBasics open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TypeHierarchy open FSharp.Compiler.TypeRelations -//------------------------------------------------------------------------- -// Generate type variables and record them in within the scope of the -// compilation environment, which currently corresponds to the scope -// of the constraint resolution carried out by type checking. -//------------------------------------------------------------------------- - -let compgenId = mkSynId range0 unassignedTyparName - -let NewCompGenTypar (kind, rigid, staticReq, dynamicReq, error) = - Construct.NewTypar(kind, rigid, SynTypar(compgenId, staticReq, true), error, dynamicReq, [], false, false) - -let AnonTyparId m = mkSynId m unassignedTyparName - -let NewAnonTypar (kind, m, rigid, var, dyn) = - Construct.NewTypar (kind, rigid, SynTypar(AnonTyparId m, var, true), false, dyn, [], false, false) - -let NewNamedInferenceMeasureVar (_m, rigid, var, id) = - Construct.NewTypar(TyparKind.Measure, rigid, SynTypar(id, var, false), false, TyparDynamicReq.No, [], false, false) - -let NewInferenceMeasurePar () = - NewCompGenTypar (TyparKind.Measure, TyparRigidity.Flexible, TyparStaticReq.None, TyparDynamicReq.No, false) - -let NewErrorTypar () = - NewCompGenTypar (TyparKind.Type, TyparRigidity.Flexible, TyparStaticReq.None, TyparDynamicReq.No, true) - -let NewErrorMeasureVar () = - NewCompGenTypar (TyparKind.Measure, TyparRigidity.Flexible, TyparStaticReq.None, TyparDynamicReq.No, true) - -let NewInferenceType (g: TcGlobals) = - ignore g // included for future, minimizing code diffs, see https://github.com/dotnet/fsharp/pull/6804 - mkTyparTy (Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, SynTypar(compgenId, TyparStaticReq.None, true), false, TyparDynamicReq.No, [], false, false)) - -let NewErrorType () = - mkTyparTy (NewErrorTypar ()) - -let NewErrorMeasure () = - Measure.Var (NewErrorMeasureVar ()) - -let NewByRefKindInferenceType (g: TcGlobals) m = - let tp = Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, SynTypar(compgenId, TyparStaticReq.HeadType, true), false, TyparDynamicReq.No, [], false, false) - if g.byrefkind_InOut_tcr.CanDeref then - tp.SetConstraints [TyparConstraint.DefaultsTo(10, TType_app(g.byrefkind_InOut_tcr, [], g.knownWithoutNull), m)] - mkTyparTy tp - -let NewInferenceTypes g l = l |> List.map (fun _ -> NewInferenceType g) - -let FreshenTypar (g: TcGlobals) rigid (tp: Typar) = - let clearStaticReq = g.langVersion.SupportsFeature LanguageFeature.InterfacesWithAbstractStaticMembers - let staticReq = if clearStaticReq then TyparStaticReq.None else tp.StaticReq - let dynamicReq = if rigid = TyparRigidity.Rigid then TyparDynamicReq.Yes else TyparDynamicReq.No - NewCompGenTypar (tp.Kind, rigid, staticReq, dynamicReq, false) - -// QUERY: should 'rigid' ever really be 'true'? We set this when we know -// we are going to have to generalize a typar, e.g. when implementing a -// abstract generic method slot. But we later check the generalization -// condition anyway, so we could get away with a non-rigid typar. This -// would sort of be cleaner, though give errors later. -let FreshenAndFixupTypars g m rigid fctps tinst tpsorig = - let tps = tpsorig |> List.map (FreshenTypar g rigid) - let renaming, tinst = FixupNewTypars m fctps tinst tpsorig tps - tps, renaming, tinst - -let FreshenTypeInst g m tpsorig = - FreshenAndFixupTypars g m TyparRigidity.Flexible [] [] tpsorig - -let FreshMethInst g m fctps tinst tpsorig = - FreshenAndFixupTypars g m TyparRigidity.Flexible fctps tinst tpsorig - -let FreshenTypars g m tpsorig = - match tpsorig with - | [] -> [] - | _ -> - let _, _, tpTys = FreshenTypeInst g m tpsorig - tpTys - -let FreshenMethInfo m (minfo: MethInfo) = - let _, _, tpTys = FreshMethInst minfo.TcGlobals m (minfo.GetFormalTyparsOfDeclaringType m) minfo.DeclaringTypeInst minfo.FormalMethodTypars - tpTys - //------------------------------------------------------------------------- // Unification of types: solve/record equality constraints // Subsumption of types: solve/record subtyping constraints @@ -1718,8 +1639,8 @@ and SolveMemberConstraint (csenv: ConstraintSolverEnv) ignoreUnresolvedOverload let propName = nm[4..] let props = supportTys |> List.choose (fun ty -> - match NameResolution.TryFindAnonRecdFieldOfType g ty propName with - | Some (NameResolution.Item.AnonRecdField(anonInfo, tinst, i, _)) -> Some (anonInfo, tinst, i) + match TryFindAnonRecdFieldOfType g ty propName with + | Some (Item.AnonRecdField(anonInfo, tinst, i, _)) -> Some (anonInfo, tinst, i) | _ -> None) match props with | [ prop ] -> Some prop diff --git a/src/Compiler/Checking/ConstraintSolver.fsi b/src/Compiler/Checking/ConstraintSolver.fsi index eb48ce3b439..aab7c04dfec 100644 --- a/src/Compiler/Checking/ConstraintSolver.fsi +++ b/src/Compiler/Checking/ConstraintSolver.fsi @@ -15,61 +15,6 @@ open FSharp.Compiler.Text open FSharp.Compiler.TypedTree open FSharp.Compiler.TypedTreeOps -/// Create a type variable representing the use of a "_" in F# code -val NewAnonTypar: TyparKind * range * TyparRigidity * TyparStaticReq * TyparDynamicReq -> Typar - -/// Create an inference type variable -val NewInferenceType: TcGlobals -> TType - -/// Create an inference type variable for the kind of a byref pointer -val NewByRefKindInferenceType: TcGlobals -> range -> TType - -/// Create an inference type variable representing an error condition when checking an expression -val NewErrorType: unit -> TType - -/// Create an inference type variable representing an error condition when checking a measure -val NewErrorMeasure: unit -> Measure - -/// Create a list of inference type variables, one for each element in the input list -val NewInferenceTypes: TcGlobals -> 'T list -> TType list - -/// Given a set of formal type parameters and their constraints, make new inference type variables for -/// each and ensure that the constraints on the new type variables are adjusted to refer to these. -/// -/// Returns -/// 1. the new type parameters -/// 2. the instantiation mapping old type parameters to inference variables -/// 3. the inference type variables as a list of types. -val FreshenAndFixupTypars: - g: TcGlobals -> - m: range -> - rigid: TyparRigidity -> - Typars -> - TType list -> - Typars -> - Typars * TyparInstantiation * TType list - -/// Given a set of type parameters, make new inference type variables for -/// each and ensure that the constraints on the new type variables are adjusted. -/// -/// Returns -/// 1. the new type parameters -/// 2. the instantiation mapping old type parameters to inference variables -/// 3. the inference type variables as a list of types. -val FreshenTypeInst: g: TcGlobals -> range -> Typars -> Typars * TyparInstantiation * TType list - -/// Given a set of type parameters, make new inference type variables for -/// each and ensure that the constraints on the new type variables are adjusted. -/// -/// Returns the inference type variables as a list of types. -val FreshenTypars: g: TcGlobals -> range -> Typars -> TType list - -/// Given a method, which may be generic, make new inference type variables for -/// its generic parameters, and ensure that the constraints the new type variables are adjusted. -/// -/// Returns the inference type variables as a list of types. -val FreshenMethInfo: range -> MethInfo -> TType list - /// Information about the context of a type equation. [] type ContextInfo = diff --git a/src/Compiler/Checking/NameResolution.fs b/src/Compiler/Checking/NameResolution.fs index 5afdada9b05..cbea7f4cf6f 100644 --- a/src/Compiler/Checking/NameResolution.fs +++ b/src/Compiler/Checking/NameResolution.fs @@ -1566,6 +1566,85 @@ let FreshenUnionCaseRef (ncenv: NameResolver) m (ucref: UnionCaseRef) = let FreshenRecdFieldRef (ncenv: NameResolver) m (rfref: RecdFieldRef) = RecdFieldInfo(ncenv.InstantiationGenerator m (rfref.Tycon.Typars m), rfref) +//------------------------------------------------------------------------- +// Generate type variables and record them in within the scope of the +// compilation environment, which currently corresponds to the scope +// of the constraint resolution carried out by type checking. +//------------------------------------------------------------------------- + +let compgenId = mkSynId range0 unassignedTyparName + +let NewCompGenTypar (kind, rigid, staticReq, dynamicReq, error) = + Construct.NewTypar(kind, rigid, SynTypar(compgenId, staticReq, true), error, dynamicReq, [], false, false) + +let AnonTyparId m = mkSynId m unassignedTyparName + +let NewAnonTypar (kind, m, rigid, var, dyn) = + Construct.NewTypar (kind, rigid, SynTypar(AnonTyparId m, var, true), false, dyn, [], false, false) + +let NewNamedInferenceMeasureVar (_m: range, rigid, var, id) = + Construct.NewTypar(TyparKind.Measure, rigid, SynTypar(id, var, false), false, TyparDynamicReq.No, [], false, false) + +let NewInferenceMeasurePar () = + NewCompGenTypar (TyparKind.Measure, TyparRigidity.Flexible, TyparStaticReq.None, TyparDynamicReq.No, false) + +let NewErrorTypar () = + NewCompGenTypar (TyparKind.Type, TyparRigidity.Flexible, TyparStaticReq.None, TyparDynamicReq.No, true) + +let NewErrorMeasureVar () = + NewCompGenTypar (TyparKind.Measure, TyparRigidity.Flexible, TyparStaticReq.None, TyparDynamicReq.No, true) + +let NewInferenceType (g: TcGlobals) = + ignore g // included for future, minimizing code diffs, see https://github.com/dotnet/fsharp/pull/6804 + mkTyparTy (Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, SynTypar(compgenId, TyparStaticReq.None, true), false, TyparDynamicReq.No, [], false, false)) + +let NewErrorType () = + mkTyparTy (NewErrorTypar ()) + +let NewErrorMeasure () = + Measure.Var (NewErrorMeasureVar ()) + +let NewByRefKindInferenceType (g: TcGlobals) m = + let tp = Construct.NewTypar (TyparKind.Type, TyparRigidity.Flexible, SynTypar(compgenId, TyparStaticReq.HeadType, true), false, TyparDynamicReq.No, [], false, false) + if g.byrefkind_InOut_tcr.CanDeref then + tp.SetConstraints [TyparConstraint.DefaultsTo(10, TType_app(g.byrefkind_InOut_tcr, [], g.knownWithoutNull), m)] + mkTyparTy tp + +let NewInferenceTypes g l = l |> List.map (fun _ -> NewInferenceType g) + +let FreshenTypar (g: TcGlobals) rigid (tp: Typar) = + let clearStaticReq = g.langVersion.SupportsFeature LanguageFeature.InterfacesWithAbstractStaticMembers + let staticReq = if clearStaticReq then TyparStaticReq.None else tp.StaticReq + let dynamicReq = if rigid = TyparRigidity.Rigid then TyparDynamicReq.Yes else TyparDynamicReq.No + NewCompGenTypar (tp.Kind, rigid, staticReq, dynamicReq, false) + +// QUERY: should 'rigid' ever really be 'true'? We set this when we know +// we are going to have to generalize a typar, e.g. when implementing a +// abstract generic method slot. But we later check the generalization +// condition anyway, so we could get away with a non-rigid typar. This +// would sort of be cleaner, though give errors later. +let FreshenAndFixupTypars g m rigid fctps tinst tpsorig = + let tps = tpsorig |> List.map (FreshenTypar g rigid) + let renaming, tinst = FixupNewTypars m fctps tinst tpsorig tps + tps, renaming, tinst + +let FreshenTypeInst g m tpsorig = + FreshenAndFixupTypars g m TyparRigidity.Flexible [] [] tpsorig + +let FreshMethInst g m fctps tinst tpsorig = + FreshenAndFixupTypars g m TyparRigidity.Flexible fctps tinst tpsorig + +let FreshenTypars g m tpsorig = + match tpsorig with + | [] -> [] + | _ -> + let _, _, tpTys = FreshenTypeInst g m tpsorig + tpTys + +let FreshenMethInfo m (minfo: MethInfo) = + let _, _, tpTys = FreshMethInst minfo.TcGlobals m (minfo.GetFormalTyparsOfDeclaringType m) minfo.DeclaringTypeInst minfo.FormalMethodTypars + tpTys + /// This must be called after fetching unqualified items that may need to be freshened /// or have type instantiations let ResolveUnqualifiedItem (ncenv: NameResolver) nenv m res = @@ -3082,8 +3161,9 @@ let rec ResolveExprLongIdentPrim sink (ncenv: NameResolver) first fullyQualified |> CollectResults success match tyconSearch () with - | Result ((resInfo, tcref) :: _) -> - let item = Item.Types(id.idText, [ generalizedTyconRef ncenv.g tcref ]) + | Result((resInfo, tcref) :: _) -> + let _, _, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars m) + let item = Item.Types(id.idText, [TType_app(tcref, tyargs, ncenv.g.knownWithoutNull)]) success (resInfo, item) | _ -> @@ -3447,9 +3527,12 @@ let ResolveTypeLongIdentInTyconRef sink (ncenv: NameResolver) nenv typeNameResIn | id :: rest -> ForceRaise (ResolveTypeLongIdentInTyconRefPrim ncenv typeNameResInfo ad ResolutionInfo.Empty PermitDirectReferenceToGeneratedType.No 0 m tcref id rest) ResolutionInfo.SendEntityPathToSink(sink, ncenv, nenv, ItemOccurence.Use, ad, resInfo, ResultTyparChecker(fun () -> true)) - let item = Item.Types(tcref.DisplayName, [FreshenTycon ncenv m tcref]) - CallNameResolutionSink sink (rangeOfLid lid, nenv, item, emptyTyparInst, ItemOccurence.UseInType, ad) - tcref + + let _, tinst, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars m) + let item = Item.Types(tcref.DisplayName, [TType_app(tcref, tyargs, ncenv.g.knownWithoutNull)]) + CallNameResolutionSink sink (rangeOfLid lid, nenv, item, tinst, ItemOccurence.UseInType, ad) + + tcref, tyargs /// Create an UndefinedName error with details let SuggestTypeLongIdentInModuleOrNamespace depth (modref: ModuleOrNamespaceRef) amap ad m (id: Ident) = @@ -3593,7 +3676,6 @@ let rec ResolveTypeLongIdentPrim sink (ncenv: NameResolver) occurence first full let r = AddResults searchSoFar (modulSearchFailed()) AtMostOneResult m2 (r |?> (fun tcrefs -> CheckForTypeLegitimacyAndMultipleGenericTypeAmbiguities (tcrefs, typeNameResInfo, genOk, m))) - /// Resolve a long identifier representing a type and report it let ResolveTypeLongIdentAux sink (ncenv: NameResolver) occurence fullyQualified nenv ad (lid: Ident list) staticResInfo genOk = let m = rangeOfLid lid @@ -3608,15 +3690,20 @@ let ResolveTypeLongIdentAux sink (ncenv: NameResolver) occurence fullyQualified match res with | Result (resInfo, tcref) -> ResolutionInfo.SendEntityPathToSink(sink, ncenv, nenv, ItemOccurence.UseInType, ad, resInfo, ResultTyparChecker(fun () -> true)) - let item = Item.Types(tcref.DisplayName, [FreshenTycon ncenv m tcref]) - CallNameResolutionSink sink (m, nenv, item, emptyTyparInst, occurence, ad) - | _ -> () - res + + let _, tinst, tyargs = FreshenTypeInst ncenv.g m (tcref.Typars m) + let item = Item.Types(tcref.DisplayName, [TType_app(tcref, tyargs, ncenv.g.knownWithoutNull)]) + CallNameResolutionSink sink (m, nenv, item, tinst, occurence, ad) + + Result(resInfo, tcref, tyargs) + + | Exception exn -> + Exception exn /// Resolve a long identifier representing a type and report it let ResolveTypeLongIdent sink ncenv occurence fullyQualified nenv ad lid staticResInfo genOk = let res = ResolveTypeLongIdentAux sink ncenv occurence fullyQualified nenv ad lid staticResInfo genOk - (res |?> fun (resInfo, tcref) -> (resInfo.EnclosingTypeInst, tcref)) + res |?> fun (resInfo, tcref, ttypes) -> (resInfo.EnclosingTypeInst, tcref, ttypes) //------------------------------------------------------------------------- // Resolve F#/IL "." syntax in records etc. diff --git a/src/Compiler/Checking/NameResolution.fsi b/src/Compiler/Checking/NameResolution.fsi index 43cfdd12d5c..c80125f1862 100755 --- a/src/Compiler/Checking/NameResolution.fsi +++ b/src/Compiler/Checking/NameResolution.fsi @@ -676,6 +676,67 @@ exception internal UpperCaseIdentifierInPattern of range /// Generate a new reference to a record field with a fresh type instantiation val FreshenRecdFieldRef: NameResolver -> range -> RecdFieldRef -> RecdFieldInfo +/// Create a type variable representing the use of a "_" in F# code +val NewAnonTypar: TyparKind * range * TyparRigidity * TyparStaticReq * TyparDynamicReq -> Typar + +val NewNamedInferenceMeasureVar: range * TyparRigidity * TyparStaticReq * Ident -> Typar + +val NewNamedInferenceMeasureVar: range * TyparRigidity * TyparStaticReq * Ident -> Typar + +val NewInferenceMeasurePar: unit -> Typar + +/// Create an inference type variable +val NewInferenceType: TcGlobals -> TType + +/// Create an inference type variable for the kind of a byref pointer +val NewByRefKindInferenceType: TcGlobals -> range -> TType + +/// Create an inference type variable representing an error condition when checking an expression +val NewErrorType: unit -> TType + +/// Create an inference type variable representing an error condition when checking a measure +val NewErrorMeasure: unit -> Measure + +/// Create a list of inference type variables, one for each element in the input list +val NewInferenceTypes: TcGlobals -> 'T list -> TType list + +/// Given a set of type parameters, make new inference type variables for +/// each and ensure that the constraints on the new type variables are adjusted. +/// +/// Returns the inference type variables as a list of types. +val FreshenTypars: g: TcGlobals -> range -> Typars -> TType list + +/// Given a method, which may be generic, make new inference type variables for +/// its generic parameters, and ensure that the constraints the new type variables are adjusted. +/// +/// Returns the inference type variables as a list of types. +val FreshenMethInfo: range -> MethInfo -> TType list + +/// Given a set of formal type parameters and their constraints, make new inference type variables for +/// each and ensure that the constraints on the new type variables are adjusted to refer to these. +/// +/// Returns +/// 1. the new type parameters +/// 2. the instantiation mapping old type parameters to inference variables +/// 3. the inference type variables as a list of types. +val FreshenAndFixupTypars: + g: TcGlobals -> + m: range -> + rigid: TyparRigidity -> + fctps: Typars -> + tinst: TType list -> + tpsorig: Typar list -> + Typar list * TyparInstantiation * TTypes + +/// Given a set of type parameters, make new inference type variables for +/// each and ensure that the constraints on the new type variables are adjusted. +/// +/// Returns +/// 1. the new type parameters +/// 2. the instantiation mapping old type parameters to inference variables +/// 3. the inference type variables as a list of types. +val FreshenTypeInst: g: TcGlobals -> m: range -> tpsorig: Typar list -> Typar list * TyparInstantiation * TTypes + /// Resolve a long identifier to a namespace, module. val internal ResolveLongIdentAsModuleOrNamespace: sink: TcResultsSink -> @@ -733,7 +794,7 @@ val internal ResolveTypeLongIdentInTyconRef: m: range -> tcref: TyconRef -> lid: Ident list -> - TyconRef + TyconRef * TypeInst /// Resolve a long identifier to a type definition val internal ResolveTypeLongIdent: @@ -746,7 +807,7 @@ val internal ResolveTypeLongIdent: lid: Ident list -> staticResInfo: TypeNameResolutionStaticArgsInfo -> genOk: PermitDirectReferenceToGeneratedType -> - ResultOrException + ResultOrException /// Resolve a long identifier to a field val internal ResolveField: diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index acbc02f6c98..b3d6261d60a 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -326,6 +326,49 @@ open System """ findSymbolUseByName "IDisposable" checkResults |> ignore + + [] + let ``Interface 04 - Type arg`` () = + let _, checkResults = getParseAndCheckResults """ +open System.Collections.Generic + +IList +""" + let symbolUse = findSymbolUseByName "IList`1" checkResults + let _, typeArg = symbolUse.GenericArguments[0] + typeArg.Format(symbolUse.DisplayContext) |> shouldEqual "int" + + [] + let ``Interface 05 - Type arg`` () = + let _, checkResults = getParseAndCheckResults """ +type I<'T> = + abstract M: 'T -> unit + +{ new I<_> with + member this.M(i: int) = () } +""" + let symbolUse = + getSymbolUses checkResults + |> Seq.findBack (fun symbolUse -> symbolUse.Symbol.DisplayName = "I") + + let _, typeArg = symbolUse.GenericArguments[0] + typeArg.Format(symbolUse.DisplayContext) |> shouldEqual "int" + + [] + let ``Interface 06 - Type arg`` () = + let _, checkResults = getParseAndCheckResults """ +type I<'T> = + abstract M: 'T -> unit + +{ new I with + member this.M _ = () } +""" + let symbolUse = + getSymbolUses checkResults + |> Seq.findBack (fun symbolUse -> symbolUse.Symbol.DisplayName = "I") + + let _, typeArg = symbolUse.GenericArguments[0] + typeArg.Format(symbolUse.DisplayContext) |> shouldEqual "int" [] let ``FSharpType.Format can use prefix representations`` () =