diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 55a58c7f04e4c..bc15ebb5351b3 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1949,21 +1949,34 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = of nkBracketExpr: # a[i] = x # --> `[]=`(a, i, x) + # try builtin subscript for LHS first: a = semSubscript(c, a, {efLValue}) if a == nil: - result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "[]=")) - result.add(n[1]) if mode == noOverloadedSubscript: - bracketNotFoundError(c, result, {}) - return errorNode(c, n) + # `[]=` overloads failed and builtin subscript failed, try `[]` overloads for LHS + # will error if not found: + a = semExprWithType(c, n[0], {efLValue}) else: + # magic overload of `[]=` will always match so cannot check for mismatch here, + # will go to above `if` branch instead + result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "[]=")) + result.add(n[1]) result = semExprNoType(c, result) return result of nkCurlyExpr: # a{i} = x --> `{}=`(a, i, x) + # no builtin behavior/magic overloads for curly subscript, + # try `{}=` overloads first then try `{}` overloads for LHS: + let nOrig = n.copyTree result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "{}=")) result.add(n[1]) - return semExprNoType(c, result) + result = semOverloadedCallAnalyseEffects(c, result, result.copyTree, {efNoUndeclared}) + if result != nil: + result = afterCallActions(c, result, nOrig, {}) + return + else: + # will error if `{}` overloads not found: + a = semExprWithType(c, a, {efLValue}) of nkPar, nkTupleConstr: if a.len >= 2 or a.kind == nkTupleConstr: # unfortunately we need to rewrite ``(x, y) = foo()`` already here so diff --git a/tests/errmsgs/t22753.nim b/tests/errmsgs/t22753.nim index 8a504109a81ce..39f018dd9b89b 100644 --- a/tests/errmsgs/t22753.nim +++ b/tests/errmsgs/t22753.nim @@ -1,50 +1,57 @@ discard """ cmd: "nim check --hints:off $file" -errormsg: "type mismatch" +action: "reject" nimoutFull: true nimout: ''' -t22753.nim(51, 13) Error: array expects two type parameters -t22753.nim(52, 1) Error: expression 'x' has no type (or is ambiguous) -t22753.nim(52, 1) Error: expression 'x' has no type (or is ambiguous) -t22753.nim(52, 2) Error: type mismatch: got <> +t22753.nim(58, 13) Error: array expects two type parameters +t22753.nim(59, 1) Error: expression 'x' has no type (or is ambiguous) +t22753.nim(59, 1) Error: expression 'x' has no type (or is ambiguous) +t22753.nim(59, 1) Error: expression 'x' has no type (or is ambiguous) +t22753.nim(59, 1) Error: expression 'x' has no type (or is ambiguous) +t22753.nim(59, 2) Error: type mismatch: got <> but expected one of: -proc `[]=`(s: var string; i: BackwardsIndex; x: char) +proc `[]`(s: string; i: BackwardsIndex): char first type mismatch at position: 2 required type for i: BackwardsIndex but expression '0' is of type: int literal(0) -proc `[]=`[I: Ordinal; T, S](a: T; i: I; x: sink S) +proc `[]`(s: var string; i: BackwardsIndex): var char + first type mismatch at position: 2 + required type for i: BackwardsIndex + but expression '0' is of type: int literal(0) +proc `[]`[I: Ordinal; T](a: T; i: I): T first type mismatch at position: 0 -proc `[]=`[Idx, T; U, V: Ordinal](a: var array[Idx, T]; x: HSlice[U, V]; - b: openArray[T]) +proc `[]`[Idx, T; U, V: Ordinal](a: array[Idx, T]; x: HSlice[U, V]): seq[T] first type mismatch at position: 2 - required type for x: HSlice[[]=.U, []=.V] + required type for x: HSlice[[].U, [].V] but expression '0' is of type: int literal(0) -proc `[]=`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T) +proc `[]`[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T first type mismatch at position: 2 required type for i: BackwardsIndex but expression '0' is of type: int literal(0) -proc `[]=`[T, U: Ordinal](s: var string; x: HSlice[T, U]; b: string) +proc `[]`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T first type mismatch at position: 2 - required type for x: HSlice[[]=.T, []=.U] + required type for i: BackwardsIndex but expression '0' is of type: int literal(0) -proc `[]=`[T; U, V: Ordinal](s: var seq[T]; x: HSlice[U, V]; b: openArray[T]) +proc `[]`[T, U: Ordinal](s: string; x: HSlice[T, U]): string first type mismatch at position: 2 - required type for x: HSlice[[]=.U, []=.V] + required type for x: HSlice[[].T, [].U] + but expression '0' is of type: int literal(0) +proc `[]`[T; U, V: Ordinal](s: openArray[T]; x: HSlice[U, V]): seq[T] + first type mismatch at position: 2 + required type for x: HSlice[[].U, [].V] + but expression '0' is of type: int literal(0) +proc `[]`[T](s: openArray[T]; i: BackwardsIndex): T + first type mismatch at position: 2 + required type for i: BackwardsIndex but expression '0' is of type: int literal(0) -proc `[]=`[T](s: var openArray[T]; i: BackwardsIndex; x: T) +proc `[]`[T](s: var openArray[T]; i: BackwardsIndex): var T first type mismatch at position: 2 required type for i: BackwardsIndex but expression '0' is of type: int literal(0) -template `[]=`(a: WideCStringObj; idx: int; val: Utf16Char) - first type mismatch at position: 3 - required type for val: Utf16Char - but expression '9' is of type: int literal(9) -template `[]=`(s: string; i: int; val: char) - first type mismatch at position: 3 - required type for val: char - but expression '9' is of type: int literal(9) -expression: x[0] = 9 +expression: x[0] +t22753.nim(59, 2) Error: expression '' has no type (or is ambiguous) +t22753.nim(59, 2) Error: '' cannot be assigned to ''' """ diff --git a/tests/specialops/tsetterfallbacksubscript.nim b/tests/specialops/tsetterfallbacksubscript.nim new file mode 100644 index 0000000000000..eb04e1b9f6077 --- /dev/null +++ b/tests/specialops/tsetterfallbacksubscript.nim @@ -0,0 +1,25 @@ +type Foo = object + x, y: float + +proc `[]`(foo: var Foo, i: int): var float = + if i == 0: + result = foo.x + else: + result = foo.y + +var pt = Foo(x: 0.0, y: 0.0) +pt[0] += 1.0 # <-- fine +`[]`(pt, 0) = 1.0 # <-- fine +pt[0] = 1.0 # <-- does not compile + +# curly: + +proc `{}`(foo: var Foo, i: int): var float = + if i == 0: + result = foo.x + else: + result = foo.y + +pt{0} += 1.0 # <-- fine +`{}`(pt, 0) = 1.0 # <-- fine +pt{0} = 1.0 # <-- does not compile