From 2d30ebaea9160606f034463cb140439388e4113b 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 (cherry picked from commit 0448557bfec17f42acdccea2ad6a157ce620ce0d) --- 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 a94ad12722..baee5ebf24 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1169,6 +1169,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")