Skip to content

Commit 5fd183f

Browse files
dsymebaronfel
authored andcommitted
nameof fixes (#9498)
1 parent 25db4ec commit 5fd183f

File tree

3 files changed

+70
-20
lines changed

3 files changed

+70
-20
lines changed

src/absil/illib.fs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,11 @@ module List =
385385
mn 0 xs
386386
let count pred xs = List.fold (fun n x -> if pred x then n+1 else n) 0 xs
387387

388+
let headAndTail l =
389+
match l with
390+
| [] -> failwith "headAndTail"
391+
| h::t -> (h,t)
392+
388393
// WARNING: not tail-recursive
389394
let mapHeadTail fhead ftail = function
390395
| [] -> []

src/fsharp/TypeChecker.fs

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9270,38 +9270,66 @@ and TcNameOfExpr cenv env tpenv (synArg: SynExpr) =
92709270

92719271
let cleanSynArg = stripParens synArg
92729272
let m = cleanSynArg.Range
9273-
let rec check overallTyOpt expr (delayed: DelayedItem list) =
9273+
let rec check overallTyOpt resultOpt expr (delayed: DelayedItem list) =
92749274
match expr with
9275-
| LongOrSingleIdent (false, (LongIdentWithDots((id::rest) as longId, _) as lidd), _, _) ->
9275+
| LongOrSingleIdent (false, (LongIdentWithDots(longId, _) as lidd), _, _) ->
92769276
let ad = env.eAccessRights
9277-
match ResolveLongIndentAsModuleOrNamespaceOrStaticClass cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m false true OpenQualified env.eNameResEnv ad id rest true with
9278-
| Result modref when delayed.IsEmpty && modref |> List.exists (p23 >> IsEntityAccessible cenv.amap m ad) ->
9279-
() // resolved to a module or namespace, done with checks
9280-
| _ ->
9281-
let (TypeNameResolutionInfo(_, staticArgsInfo)) = GetLongIdentTypeNameInfo delayed
9282-
match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInAttribute OpenQualified env.eNameResEnv ad longId staticArgsInfo PermitDirectReferenceToGeneratedType.No with
9283-
| Result tcref when IsEntityAccessible cenv.amap m ad tcref ->
9284-
() // resolved to a type name, done with checks
9285-
| _ ->
9286-
let overallTy = match overallTyOpt with None -> NewInferenceType() | Some t -> t
9287-
let _, _ = TcLongIdentThen cenv overallTy env tpenv lidd delayed
9288-
() // checked as an expression, done with checks
9289-
List.last longId
9277+
let result = defaultArg resultOpt (List.last longId)
9278+
let resolvedToModuleOrNamespaceName =
9279+
if delayed.IsEmpty then
9280+
let id,rest = List.headAndTail longId
9281+
match ResolveLongIndentAsModuleOrNamespaceOrStaticClass cenv.tcSink ResultCollectionSettings.AllResults cenv.amap m false true OpenQualified env.eNameResEnv ad id rest true with
9282+
| Result modref when delayed.IsEmpty && modref |> List.exists (p23 >> IsEntityAccessible cenv.amap m ad) ->
9283+
true // resolved to a module or namespace, done with checks
9284+
| _ ->
9285+
false
9286+
else
9287+
false
9288+
if resolvedToModuleOrNamespaceName then result else
9289+
9290+
let resolvedToTypeName =
9291+
if (match delayed with [DelayedTypeApp _] | [] -> true | _ -> false) then
9292+
let (TypeNameResolutionInfo(_, staticArgsInfo)) = GetLongIdentTypeNameInfo delayed
9293+
match ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.UseInAttribute OpenQualified env.eNameResEnv ad longId staticArgsInfo PermitDirectReferenceToGeneratedType.No with
9294+
| Result tcref when (match delayed with [DelayedTypeApp _] | [] -> true | _ -> false) && IsEntityAccessible cenv.amap m ad tcref ->
9295+
true // resolved to a type name, done with checks
9296+
| _ ->
9297+
false
9298+
else
9299+
false
9300+
if resolvedToTypeName then result else
92909301

9302+
let overallTy = match overallTyOpt with None -> NewInferenceType() | Some t -> t
9303+
9304+
// This will raise an error if resolution doesn't succeed
9305+
let _, _ = TcLongIdentThen cenv overallTy env tpenv lidd delayed
9306+
result // checked as an expression, done with checks
9307+
9308+
// expr<tyargs> allowed, even with qualifications
92919309
| SynExpr.TypeApp (hd, _, types, _, _, _, m) ->
9292-
check overallTyOpt hd (DelayedTypeApp(types, m, m) :: delayed)
9310+
check overallTyOpt resultOpt hd (DelayedTypeApp(types, m, m) :: delayed)
92939311

9294-
| SynExpr.Paren(expr, _, _, _) when overallTyOpt.IsNone && delayed.IsEmpty ->
9295-
check overallTyOpt expr []
9312+
// expr.ID allowed
9313+
| SynExpr.DotGet (hd, _, LongIdentWithDots(longId, _), _) ->
9314+
let result = defaultArg resultOpt (List.last longId)
9315+
check overallTyOpt (Some result) hd ((DelayedDotLookup (longId, expr.RangeSansAnyExtraDot)) :: delayed)
92969316

9317+
// "(expr)" allowed with no subsequent qualifications
9318+
| SynExpr.Paren(expr, _, _, _) when delayed.IsEmpty && overallTyOpt.IsNone ->
9319+
check overallTyOpt resultOpt expr delayed
9320+
9321+
// expr : type" allowed with no subsequent qualifications
92979322
| SynExpr.Typed (synBodyExpr, synType, _m) when delayed.IsEmpty && overallTyOpt.IsNone ->
92989323
let tgtTy, _tpenv = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv synType
9299-
check (Some tgtTy) synBodyExpr []
9324+
check (Some tgtTy) resultOpt synBodyExpr delayed
93009325

93019326
| _ ->
93029327
error (Error(FSComp.SR.expressionHasNoName(), m))
93039328

9304-
let lastIdent = check None cleanSynArg []
9329+
let lastIdent = check None None cleanSynArg []
9330+
TcNameOfExprResult cenv lastIdent m
9331+
9332+
and TcNameOfExprResult cenv (lastIdent: Ident) m =
93059333
let constRange = mkRange m.FileName m.Start (mkPos m.StartLine (m.StartColumn + lastIdent.idText.Length + 2)) // `2` are for quotes
93069334
Expr.Const(Const.String(lastIdent.idText), constRange, cenv.g.string_ty)
93079335

@@ -9824,8 +9852,21 @@ and TcItemThen cenv overallTy env tpenv (item, mItem, rest, afterResolution) del
98249852
// - it isn't a CtorValUsedAsSuperInit
98259853
// - it isn't a CtorValUsedAsSelfInit
98269854
// - it isn't a VSlotDirectCall (uses of base values do not take type arguments
9855+
// Allow `nameof<'T>` for a generic parameter
9856+
match vref with
9857+
| _ when isNameOfValRef cenv.g vref && cenv.g.langVersion.SupportsFeature LanguageFeature.NameOf ->
9858+
match tys with
9859+
| [SynType.Var((Typar(id, _, false) as tp), _m)] ->
9860+
let _tp', tpenv = TcTyparOrMeasurePar None cenv env ImplicitlyBoundTyparsAllowed.NoNewTypars tpenv tp
9861+
let vexp = TcNameOfExprResult cenv id mExprAndTypeArgs
9862+
let vexpFlex = MakeApplicableExprNoFlex cenv vexp
9863+
PropagateThenTcDelayed cenv overallTy env tpenv mExprAndTypeArgs vexpFlex cenv.g.string_ty ExprAtomicFlag.Atomic otherDelayed
9864+
| _ ->
9865+
error (Error(FSComp.SR.expressionHasNoName(), mExprAndTypeArgs))
9866+
| _ ->
98279867
let checkTys tpenv kinds = TcTypesOrMeasures (Some kinds) cenv NewTyparsOK CheckCxs ItemOccurence.UseInType env tpenv tys mItem
98289868
let _, vexp, isSpecial, _, _, tpenv = TcVal true cenv env tpenv vref (Some (NormalValUse, checkTys)) (Some afterResolution) mItem
9869+
98299870
let vexpFlex = (if isSpecial then MakeApplicableExprNoFlex cenv vexp else MakeApplicableExprWithFlex cenv env vexp)
98309871
// We need to eventually record the type resolution for an expression, but this is done
98319872
// inside PropagateThenTcDelayed, so we don't have to explicitly call 'CallExprHasTypeSink' here

src/fsharp/TypedTreeOps.fsi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,7 +2279,11 @@ val (|EnumExpr|_|) : TcGlobals -> Expr -> Expr option
22792279
val (|TypeOfExpr|_|) : TcGlobals -> Expr -> TType option
22802280

22812281
val (|TypeDefOfExpr|_|) : TcGlobals -> Expr -> TType option
2282+
2283+
val isNameOfValRef: TcGlobals -> ValRef -> bool
2284+
22822285
val (|NameOfExpr|_|) : TcGlobals -> Expr -> TType option
2286+
22832287
val (|SeqExpr|_|) : TcGlobals -> Expr -> unit option
22842288

22852289
val EvalLiteralExprOrAttribArg: TcGlobals -> Expr -> Expr

0 commit comments

Comments
 (0)