mirror of
https://github.com/nim-lang/Nim.git
synced 2026-05-24 21:59:52 +00:00
fixes #25617 This pull request introduces a stricter check for parameter type relations in the `procParamTypeRel` procedure. Specifically, it ensures that two types are not only structurally equal but also have the same backend type, taking type aliases into account. Type relation checks: * [`compiler/sigmatch.nim`](diffhunk://#diff-251afcd01d239369019495096c187998dd6695b6457528953237a7e4a10f7138R787-R789): In `procParamTypeRel`, added a check to ensure that if two types are considered equal (`isEqual`), they must also have the same backend type (using `sameBackendTypePickyAliases`). If not, the result is set to `isNone`, preventing false positives when type aliases differ.
This commit is contained in:
@@ -35,6 +35,10 @@ errors.
|
||||
|
||||
- Adds a new warning `--warning:ImplicitRangeConversion` that detects downsizing implicit conversions to range types (e.g., `int -> range[0..255]` or `range[1..256] -> range[0..255]`) that could cause runtime panics. Safe conversions like `range[0..255] -> range[0..65535]` and explicit casts do not trigger warnings. `int` to `Natural` and `Positive` conversions do not trigger warnings, which can be enabled with `--warning:systemRangeConversion`.
|
||||
|
||||
- Procedure compatibility also checks the backend representation of the
|
||||
parameter and result types, not just their source-level shape. Use
|
||||
`--legacy:procParamTypeBackendAliases` to restore the older behavior.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
[//]: # "Additions:"
|
||||
|
||||
@@ -259,6 +259,9 @@ type
|
||||
## Old transformation for closures in JS backend
|
||||
noPanicOnExcept
|
||||
## don't panic on bare except
|
||||
procParamTypeBackendAliases
|
||||
## Keep the old proc type compatibility rules that ignore backend
|
||||
## c type aliases.
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||
|
||||
@@ -784,6 +784,17 @@ proc procParamTypeRel(c: var TCandidate; f, a: PType): TTypeRelation =
|
||||
# if f is metatype.
|
||||
result = typeRel(c, f, a)
|
||||
|
||||
if result == isEqual and
|
||||
procParamTypeBackendAliases notin c.c.config.legacyFeatures:
|
||||
# Ensure types that are semantically equal also match at the backend level.
|
||||
# E.g. reject assigning proc(csize_t) to proc(uint) since these map to
|
||||
# different C types (size_t vs unsigned long long).
|
||||
let fCheck = concreteType(c, f)
|
||||
let aCheck = concreteType(c, a)
|
||||
if fCheck != nil and aCheck != nil and
|
||||
not sameBackendTypePickyAliases(fCheck, aCheck):
|
||||
result = isNone
|
||||
|
||||
if result <= isSubrange or inconsistentVarTypes(f, a):
|
||||
result = isNone
|
||||
|
||||
|
||||
@@ -897,7 +897,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
c.flags = oldFlags
|
||||
|
||||
if x == y: return true
|
||||
let aliasSkipSet = maybeSkipRange({tyAlias})
|
||||
let aliasSkipSet = maybeSkipRange({tyAlias, tyInferred})
|
||||
var a = skipTypes(x, aliasSkipSet)
|
||||
while a.kind == tyUserTypeClass and tfResolved in a.flags:
|
||||
a = skipTypes(a.last, aliasSkipSet)
|
||||
|
||||
@@ -1024,6 +1024,9 @@ These are the major type classes:
|
||||
* procedural type
|
||||
* generic type
|
||||
|
||||
The compiler's internal type zoo is richer than this summary suggests:
|
||||
some types that are structurally equal still differ in backend representation.
|
||||
|
||||
|
||||
Ordinal types
|
||||
-------------
|
||||
@@ -2174,6 +2177,10 @@ Procedural type
|
||||
A procedural type is internally a pointer to a procedure. `nil` is
|
||||
an allowed value for a variable of a procedural type.
|
||||
|
||||
Procedure compatibility also checks the backend representation of the
|
||||
parameter and result types, not just their source-level shape. Use
|
||||
`--legacy:procParamTypeBackendAliases` to restore the older behavior.
|
||||
|
||||
Examples:
|
||||
|
||||
```nim
|
||||
|
||||
@@ -176,6 +176,42 @@ block t6462:
|
||||
var s = SeqGen[int](fil: FilterMixin[int](test: nil, trans: nil))
|
||||
doAssert s.test() == nil
|
||||
|
||||
block concept_with_cint:
|
||||
# Generic proc matching through concepts with cint should still work
|
||||
type
|
||||
FilterMixin[T] = ref object
|
||||
test: (T) -> bool
|
||||
trans: (T) -> T
|
||||
|
||||
SeqGen[T] = ref object
|
||||
fil: FilterMixin[T]
|
||||
|
||||
WithFilter[T] = concept a
|
||||
a.fil is FilterMixin[T]
|
||||
|
||||
proc test[T](a: WithFilter[T]): (T) -> bool =
|
||||
a.fil.test
|
||||
|
||||
var s = SeqGen[cint](fil: FilterMixin[cint](test: nil, trans: nil))
|
||||
doAssert s.test() == nil
|
||||
|
||||
block concept_with_int:
|
||||
type
|
||||
FilterMixin[T] = ref object
|
||||
test: (T) -> bool
|
||||
trans: (T) -> T
|
||||
|
||||
SeqGen[T] = ref object
|
||||
fil: FilterMixin[T]
|
||||
|
||||
WithFilter[T] = concept a
|
||||
a.fil is FilterMixin[T]
|
||||
|
||||
proc test[T](a: WithFilter[T]): (T) -> bool =
|
||||
a.fil.test
|
||||
|
||||
var s = SeqGen[int](fil: FilterMixin[int](test: nil, trans: nil))
|
||||
doAssert s.test() == nil
|
||||
|
||||
|
||||
block t6770:
|
||||
|
||||
44
tests/proc/tbackendtypealias.nim
Normal file
44
tests/proc/tbackendtypealias.nim
Normal file
@@ -0,0 +1,44 @@
|
||||
# bug #25617
|
||||
# Ensure that proc types with backend type alias mismatches
|
||||
# (e.g. uint vs csize_t) are rejected at the Nim level rather
|
||||
# than producing invalid C code.
|
||||
|
||||
discard """
|
||||
cmd: "nim check --hints:off --warnings:off --errorMax:0 $file"
|
||||
action: "reject"
|
||||
nimout: '''
|
||||
tbackendtypealias.nim(21, 7) Error: type mismatch: got <proc (len: csize_t){.closure.}> but expected 'proc (len: uint){.closure.}'
|
||||
tbackendtypealias.nim(28, 7) Error: type mismatch: got <proc (len: uint){.closure.}> but expected 'proc (len: csize_t){.closure.}'
|
||||
'''
|
||||
"""
|
||||
|
||||
block direct_assignment:
|
||||
# Direct proc variable assignment with backend type alias mismatch
|
||||
var
|
||||
a: proc (len: uint)
|
||||
b: proc (len: csize_t)
|
||||
c = a
|
||||
c = b
|
||||
|
||||
block direct_assignment_reverse:
|
||||
var
|
||||
a: proc (len: csize_t)
|
||||
b: proc (len: uint)
|
||||
c = a
|
||||
c = b
|
||||
|
||||
block same_backend_type:
|
||||
# Same backend type should still work
|
||||
var
|
||||
a: proc (len: uint)
|
||||
b: proc (len: uint)
|
||||
c = a
|
||||
c = b
|
||||
|
||||
block cint_same_type:
|
||||
# cint to cint should work
|
||||
var
|
||||
a: proc (len: cint)
|
||||
b: proc (len: cint)
|
||||
c = a
|
||||
c = b
|
||||
Reference in New Issue
Block a user