From b38857474952343b18f4258f79ab16f5e42804dc Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 14 Apr 2025 00:17:03 +0300 Subject: [PATCH 1/4] implement setter fallback for subscripts follows up #24871 --- compiler/semexprs.nim | 22 ++++++++++------ tests/specialops/tsetterfallbacksubscript.nim | 25 +++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 tests/specialops/tsetterfallbacksubscript.nim diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 55a58c7f04e4..b453131f5807 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1951,19 +1951,27 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = # --> `[]=`(a, i, x) 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: + 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) - result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "{}=")) - result.add(n[1]) - return semExprNoType(c, result) + let nOrig = n.copyTree + var asgnCall = buildOverloadedSubscripts(n[0], getIdent(c.cache, "[]=")) + asgnCall.add(n[1]) + result = semOverloadedCallAnalyseEffects(c, asgnCall, asgnCall.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/specialops/tsetterfallbacksubscript.nim b/tests/specialops/tsetterfallbacksubscript.nim new file mode 100644 index 000000000000..eb04e1b9f607 --- /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 From 891e107a2954a7a3237fe766aae6680778391392 Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 14 Apr 2025 01:07:47 +0300 Subject: [PATCH 2/4] fix curly subscripts --- compiler/semexprs.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index b453131f5807..aa3ed8268cdc 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1963,7 +1963,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = of nkCurlyExpr: # a{i} = x --> `{}=`(a, i, x) let nOrig = n.copyTree - var asgnCall = buildOverloadedSubscripts(n[0], getIdent(c.cache, "[]=")) + var asgnCall = buildOverloadedSubscripts(n[0], getIdent(c.cache, "{}=")) asgnCall.add(n[1]) result = semOverloadedCallAnalyseEffects(c, asgnCall, asgnCall.copyTree, {efNoUndeclared}) if result != nil: From f6fc27eedfc4d2fecdfd23b920be6303f6f3e509 Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 14 Apr 2025 16:46:25 +0300 Subject: [PATCH 3/4] update test --- tests/errmsgs/t22753.nim | 57 ++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/tests/errmsgs/t22753.nim b/tests/errmsgs/t22753.nim index 8a504109a81c..39f018dd9b89 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 ''' """ From 3f031035bfae344e8850ba96db8faf250c23dfdb Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 14 Apr 2025 18:04:46 +0300 Subject: [PATCH 4/4] clean up --- compiler/semexprs.nim | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index aa3ed8268cdc..bc15ebb5351b 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1949,6 +1949,7 @@ 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: if mode == noOverloadedSubscript: @@ -1956,16 +1957,20 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = # 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 - var asgnCall = buildOverloadedSubscripts(n[0], getIdent(c.cache, "{}=")) - asgnCall.add(n[1]) - result = semOverloadedCallAnalyseEffects(c, asgnCall, asgnCall.copyTree, {efNoUndeclared}) + result = buildOverloadedSubscripts(n[0], getIdent(c.cache, "{}=")) + result.add(n[1]) + result = semOverloadedCallAnalyseEffects(c, result, result.copyTree, {efNoUndeclared}) if result != nil: result = afterCallActions(c, result, nOrig, {}) return