From 0448557bfec17f42acdccea2ad6a157ce620ce0d Mon Sep 17 00:00:00 2001 From: Ryan McConnell Date: Thu, 11 Jun 2026 02:17:35 -0400 Subject: [PATCH] fix 25778; concept coerces incompatible types (#25781) I don't like it, but seems like this is correct. Concept type classes have to behave like other "named" type classes and participate in "bind once" mechanics or require some weird semantics. As a side note I'm pretty sure the `tuple` example in the manual explaining this is either wrong now or has regressed, but I don't think it matters because I doubt anyone thinks about this feature much. #25778 --- compiler/sigmatch.nim | 4 +++ .../conceptv2negative/tconsistentparams.nim | 28 +++++++++++++++++++ tests/concepts/tconceptsv2.nim | 14 ++++++++++ 3 files changed, 46 insertions(+) create mode 100644 tests/concepts/conceptv2negative/tconsistentparams.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index cb79823af5..9526d37290 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1168,6 +1168,10 @@ proc enterConceptMatch(c: var TCandidate; f,a: PType, flags: TTypeRelFlags): TTy if concpt.kind != tyConcept: container = concpt concpt = container.reduceToBase + # considerPreviousT-like behavior + let prev = lookup(c.bindings, concpt) + if prev != nil: + return typeRel(c, prev, a, flags) if trDontBind in flags: conceptFlags.incl mfDontBind if trCheckGeneric in flags: diff --git a/tests/concepts/conceptv2negative/tconsistentparams.nim b/tests/concepts/conceptv2negative/tconsistentparams.nim new file mode 100644 index 0000000000..c1a0c1290d --- /dev/null +++ b/tests/concepts/conceptv2negative/tconsistentparams.nim @@ -0,0 +1,28 @@ +discard """ +action: "reject" +errormsg: "type mismatch" +""" + +type + Dollarable = concept + proc `$`(x: Self): string + +proc checkEqual(x, y: Dollarable) = + if x != y: + echo $x + echo $y + +type + StateFlags = enum + sfMatch + sfSoft + + MatchKind = enum + NoFurtherMatch + NoMatch + Match + AllFurtherMatch + +proc `==`(a: set[StateFlags]; b: MatchKind): bool = true + +checkEqual({sfMatch, sfSoft}, Match) diff --git a/tests/concepts/tconceptsv2.nim b/tests/concepts/tconceptsv2.nim index d861c51c75..13f8211f5b 100644 --- a/tests/concepts/tconceptsv2.nim +++ b/tests/concepts/tconceptsv2.nim @@ -14,6 +14,8 @@ b c 1 2 +5 +test ''' """ import conceptsv2_helper @@ -600,3 +602,15 @@ block: let test = MemMapFileStream() spring(test) + +# explicit negative "bind once" + +type + Dollarable = concept + proc `$`(x: Self): string + +proc checkEqual2[T: Dollarable; S: Dollarable](x: T, y: S) = + echo $x + echo $y + +checkEqual2(5, "test")