remove fauxMatch for tyFromExpr, remove tyProxy and tyUnknown aliases (#24018)

updated version of #22193

After #22029 and the followups #23983 and #24005 which fixed issues with
it, `tyFromExpr` no longer match any proc params in generic type bodies
but delay all non-matching calls until the type is instantiated.
Previously the mechanism `fauxMatch` was used to pretend that any
failing match against `tyFromExpr` actually matched, but prevented the
instantiation of the type until later.

Since this mechanism is not needed anymore for `tyFromExpr`, it is now
only used for `tyError` to prevent cascading errors and changed to a
bool field for simplicity. A change in `semtypes` was also needed to
prevent calling `fitNode` on default param values resolving to type
`tyFromExpr` in generic procs for params with non-generic types, as this
would try to coerce the expression into a concrete type when it can't be
instantiated yet.

The aliases `tyProxy` and `tyUnknown` for `tyError` and `tyFromExpr` are
also removed for uniformity.
This commit is contained in:
metagn
2024-08-28 21:46:36 +03:00
committed by GitHub
parent ea7c2a4409
commit d3af51e3ce
15 changed files with 31 additions and 39 deletions

View File

@@ -214,7 +214,8 @@ type
tyUncheckedArray
# An array with boundaries [0,+∞]
tyProxy # used as errornous type (for idetools)
tyError # used as erroneous type (for idetools)
# as an erroneous node should match everything
tyBuiltInTypeClass
# Type such as the catch-all object, tuple, seq, etc
@@ -276,10 +277,6 @@ static:
const
tyPureObject* = tyTuple
GcTypeKinds* = {tyRef, tySequence, tyString}
tyError* = tyProxy # as an errornous node should match everything
tyUnknown* = tyFromExpr
tyUnknownTypes* = {tyError, tyFromExpr}
tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
tyUserTypeClass, tyUserTypeClassInst,

View File

@@ -96,7 +96,7 @@ proc specializeResetT(p: BProc, accessor: Rope, typ: PType) =
raiseAssert "unexpected set type kind"
of tyNone, tyEmpty, tyNil, tyUntyped, tyTyped, tyGenericInvocation,
tyGenericParam, tyOrdinal, tyOpenArray, tyForward, tyVarargs,
tyUncheckedArray, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUncheckedArray, tyError, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot,
tyAnything, tyStatic, tyFromExpr, tyConcept, tyVoid, tyIterable:
discard

View File

@@ -125,7 +125,7 @@ proc expandDefault(t: PType; info: TLineInfo): PNode =
of tyString:
result = newZero(t, info, nkStrLit)
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
tyNil, tyGenericInvocation, tyError, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
result = newZero(t, info, nkEmpty) # bug indicator

View File

@@ -195,7 +195,7 @@ proc mapType(typ: PType): TJSTypeKind =
of tyPointer:
# treat a tyPointer like a typed pointer to an array of bytes
result = etyBaseIndex
of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent:
of tyRange, tyDistinct, tyOrdinal, tyError, tyLent:
# tyLent is no-op as JS has pass-by-reference semantics
result = mapType(skipModifier t)
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt

View File

@@ -1040,7 +1040,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
else:
discard "cannot copy openArray"
of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
of tyFromExpr, tyError, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped,
tyTypeDesc, tyGenericInvocation, tyForward, tyStatic:

View File

@@ -696,12 +696,12 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
markUsed(c, info, finalCallee)
onUse(info, finalCallee)
assert finalCallee.ast != nil
if x.hasFauxMatch:
if x.matchedErrorType:
result = x.call
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
result.typ = newTypeS(x.fauxMatch, c)
if result.typ.kind == tyError: incl result.typ.flags, tfCheckedForDestructor
if containsGenericType(result.typ):
result.typ = newTypeS(tyError, c)
incl result.typ.flags, tfCheckedForDestructor
return
let gp = finalCallee.ast[genericParamsPos]
if gp.isGenericParams:

View File

@@ -2859,7 +2859,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
let verdict = semConstExpr(c, n[i])
if verdict == nil or verdict.kind != nkIntLit or verdict.intVal == 0:
localError(c.config, result.info, "concept predicate failed")
of tyUnknown: continue
of tyFromExpr: continue
else: discard
if n[i].typ == c.enforceVoidContext: #or usesResult(n[i]):
voidContext = true

View File

@@ -1385,7 +1385,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
typ = newTypeS(tyTypeDesc, c, newTypeS(tyNone, c))
typ.flags.incl tfCheckedForDestructor
else:
elif def.typ.kind != tyFromExpr:
# if def.typ != nil and def.typ.kind != tyNone:
# example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp)

View File

@@ -59,8 +59,8 @@ type
magic*: TMagic # magic of operation
baseTypeMatch: bool # needed for conversions from T to openarray[T]
# for example
fauxMatch*: TTypeKind # the match was successful only due to the use
# of error or wildcard (unknown) types.
matchedErrorType*: bool # match is considered successful after matching
# error type to avoid cascading errors
# this is used to prevent instantiations.
genericConverter*: bool # true if a generic converter needs to
# be instantiated
@@ -101,8 +101,6 @@ const
proc markUsed*(c: PContext; info: TLineInfo, s: PSym; checkStyle = true)
proc markOwnerModuleAsUsed*(c: PContext; s: PSym)
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
proc initCandidateAux(ctx: PContext,
callee: PType): TCandidate {.inline.} =
result = TCandidate(c: ctx, exactMatches: 0, subtypeMatches: 0,
@@ -813,7 +811,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
param.typ.flags.incl tfInferrableStatic
else:
param.ast = typ.n
of tyUnknown:
of tyFromExpr:
param = paramSym skVar
param.typ = typ.exactReplica
#copyType(typ, c.idgen, typ.owner)
@@ -1971,7 +1969,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if aOrig != nil:
put(c, f, aOrig)
result = isGeneric
of tyProxy:
of tyError:
result = isEqual
of tyFromExpr:
# fix the expression, so it contains the already instantiated types
@@ -2037,7 +2035,7 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
c: PContext): PNode =
result = newNodeI(kind, arg.info)
if containsGenericType(f):
if not m.hasFauxMatch:
if not m.matchedErrorType:
result.typ = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
else:
result.typ = errorType(c)
@@ -2329,13 +2327,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
of isNone:
# do not do this in ``typeRel`` as it then can't infer T in ``ref T``:
if a.kind in {tyProxy, tyUnknown}:
if a.kind == tyUnknown and c.inGenericContext > 0:
# don't bother with fauxMatch mechanism in generic type,
# reject match, typechecking will be delayed to instantiation
return nil
if a.kind == tyFromExpr: return nil
elif a.kind == tyError:
inc(m.genericMatches)
m.fauxMatch = a.kind
m.matchedErrorType = true
return arg
elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
# lift do blocks without params to lambdas
@@ -2505,7 +2500,7 @@ proc setSon(father: PNode, at: int, son: PNode) =
# we are allowed to modify the calling node in the 'prepare*' procs:
proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
if formal.kind == tyUntyped and formal.len != 1:
# {tyTypeDesc, tyUntyped, tyTyped, tyProxy}:
# {tyTypeDesc, tyUntyped, tyTyped, tyError}:
# a.typ == nil is valid
result = a
elif a.typ.isNil:

View File

@@ -200,7 +200,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
result = typeAllowedNode(marker, t.n, kind, c, flags)
of tyEmpty:
if kind in {skVar, skLet}: result = t
of tyProxy:
of tyError:
# for now same as error node; we say it's a valid type as it should
# prevent cascading errors:
result = nil

View File

@@ -776,7 +776,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
case t.kind
of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyError:
result = Zero
of tySet, tyVar: result = firstOrd(conf, t.elementType)
of tyArray: result = firstOrd(conf, t.indexType)
@@ -909,7 +909,7 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
result = lastOrd(conf, skipModifier(t))
of tyUserTypeClasses:
result = lastOrd(conf, last(t))
of tyProxy: result = Zero
of tyError: result = Zero
of tyOrdinal:
if t.hasElementType: result = lastOrd(conf, skipModifier(t))
else:

View File

@@ -282,7 +282,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
of tyUInt32: result = atomicType("uint32", mUInt32)
of tyUInt64: result = atomicType("uint64", mUInt64)
of tyVarargs: result = mapTypeToBracket("varargs", mVarargs, t, info)
of tyProxy: result = atomicType("error", mNone)
of tyError: result = atomicType("error", mNone)
of tyBuiltInTypeClass:
result = mapTypeToBracket("builtinTypeClass", mNone, t, info)
of tyUserTypeClass, tyUserTypeClassInst:

View File

@@ -59,7 +59,7 @@ type
tyOwned, tyUnused1, tyUnused2,
tyVarargsHidden,
tyUncheckedArray,
tyProxyHidden,
tyErrorHidden,
tyBuiltInTypeClassHidden,
tyUserTypeClassHidden,
tyUserTypeClassInstHidden,

View File

@@ -8,7 +8,7 @@ but expected: <T: float or string, Y>
tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)]
got: <typedesc[int], int literal(10)>
but expected: <T: float or string, Y>
tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [proxy]
tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [error]
tstatic_constrained.nim(44, 31) Error: expression '' has no type (or is ambiguous)
tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)]
got: <typedesc[byte], uint8>
@@ -16,7 +16,7 @@ but expected: <T: float or string, Y>
tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)]
got: <typedesc[byte], uint8>
but expected: <T: float or string, Y>
tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [proxy]
tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [error]
tstatic_constrained.nim(45, 34) Error: expression '' has no type (or is ambiguous)
tstatic_constrained.nim(77, 14) Error: cannot instantiate MyType [type declared in tstatic_constrained.nim(71, 5)]
got: <typedesc[float], float64>
@@ -76,4 +76,4 @@ block:
b: MyType[string, "hello"]
c: MyType[float, 10d]
d: MyOtherType[MyOtherConstraint[float],MyOtherConstraint[float]()]
e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()]
e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()]

View File

@@ -4,11 +4,11 @@ discard """
nimout:'''
tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject'
tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject'
tinheritgenericparameter.nim(36, 23) Error: object constructor needs an object type [proxy]
tinheritgenericparameter.nim(36, 23) Error: object constructor needs an object type [error]
tinheritgenericparameter.nim(36, 23) Error: expression '' has no type (or is ambiguous)
tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int'
tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int'
tinheritgenericparameter.nim(37, 23) Error: object constructor needs an object type [proxy]
tinheritgenericparameter.nim(37, 23) Error: object constructor needs an object type [error]
tinheritgenericparameter.nim(37, 23) Error: expression '' has no type (or is ambiguous)
'''
"""