-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sem: don't analyze dependent operands to
static
(#1345)
## Summary Makes instantiations such as `Generic[someProc(T)]` work, where `T` is some generic parameter (and receiving type parameter is a `static` one) -- the `someProc(T)` expression is typed once `T` is substituted, making the behaviour consistent with `array` and `range`. ## Details Fully analyzing (i.e., with `semExpr`) arbitrary expressions that might reference unresolved type variables generally doesn't work. Operands to generic invocations were eagerly analyzed (in `matchesAux`), usually resulting in errors when the operand needs to be a `static` value. Disallowing expressions dependent on unresolved type variables in this context would be a regression, since some expressions are special-cased to work (such as `sizeof(T)`). To address the problem, before typing the operand, it's first checked whether it depends on unresolved type variables. If it does, the expression is treated as a generic expression, with a `tyFromExpr` assigned as its type -- otherwise it's analyzed as usual. If the operand has an unknown type (`tyFromExpr`), it's wrapped in a conversion to a type derived from the generic parameter's constraint, to make sure the operand types later. If no concrete type can be derived from the constraint, a type mismatch is reported. To not convolute `matchesAux` further, the argument matching where the callee is a `tyGenericBody` is moved into the new `matchesType`. It does largely the same as `matchesAux`, but with everything not applicable to types removed (such as the varargs handling). --------- Co-authored-by: Saem Ghani <[email protected]>
- Loading branch information
Showing
6 changed files
with
184 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
tests/lang_callable/generics/tdependent_operands_to_static.nim
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
discard """ | ||
description: ''' | ||
Various tests for operands to `static` constrained generic type parameters | ||
where the operand's type depends on unresolved type variables. | ||
''' | ||
""" | ||
|
||
type | ||
Type1[T: static] = object ## only must be *some* static value | ||
Type2[T: static int] = object ## must a be a static int | ||
|
||
proc eval[T](x: T): T {.compileTime.} = | ||
x | ||
|
||
proc p1[T](): Type1[eval(default(T))] = discard | ||
proc p2[T](): Type2[eval(default(T))] = discard | ||
# ^^ whether the ``Type2`` can be instantiated depends on the later | ||
# supplied `T` | ||
|
||
discard p1[int]() # works | ||
discard p1[float]() # works | ||
discard p1[string]() # works | ||
|
||
discard p2[int]() # int is convertible to int -> works | ||
discard p2[float]() # float is convertible to int -> works | ||
# string is not convertible to float -> fails: | ||
doAssert not compiles(p3[string]()) |
21 changes: 21 additions & 0 deletions
21
tests/lang_callable/generics/tdependent_operands_to_static_2.nim
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
discard """ | ||
description: ''' | ||
Operands with a type not known upfront cannot be used as arguments to | ||
complex static | ||
''' | ||
errormsg: "cannot instantiate Type" | ||
line: 21 | ||
knownIssue: ''' | ||
`Type`s generic parameter is not detected as containing a `static`, thus | ||
full analysis is not disabled (which subsequently fails) | ||
''' | ||
""" | ||
|
||
type | ||
Type[T: string | static float] = object ## must be a string or static float | ||
|
||
proc eval[T](x: T): T {.compileTime.} = x | ||
|
||
# the operand's type is not known and no concrete type can be derived from | ||
# the constraint -> reject early | ||
proc p[T](): Type[eval(default(T))] = discard |