mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Canonicalize different spellings of the same integer generic parameter.
`Foo<256>`, `Foo<2_56>`, and `Foo<0x100>` are all canonically the same type. Fixes rdar://144736386.
This commit is contained in:
@@ -207,7 +207,7 @@ TYPE(PackExpansion, Type)
|
||||
TYPE(PackElement, Type)
|
||||
UNCHECKED_TYPE(TypeVariable, Type)
|
||||
UNCHECKED_TYPE(ErrorUnion, Type)
|
||||
ALWAYS_CANONICAL_TYPE(Integer, Type)
|
||||
TYPE(Integer, Type)
|
||||
ABSTRACT_SUGARED_TYPE(Sugar, Type)
|
||||
SUGARED_TYPE(TypeAlias, SugarType)
|
||||
SUGARED_TYPE(Locatable, SugarType)
|
||||
|
||||
@@ -7884,10 +7884,27 @@ class IntegerType final : public TypeBase, public llvm::FoldingSetNode {
|
||||
friend class ASTContext;
|
||||
|
||||
StringRef Value;
|
||||
// Integers may not be canonical, but don't have any structural type
|
||||
// components from which to get the ASTContext, so we need to store a
|
||||
// reference to it ourselves.
|
||||
const ASTContext &Context;
|
||||
|
||||
static const ASTContext *
|
||||
getCanonicalIntegerLiteralContext(StringRef value, const ASTContext &ctx) {
|
||||
for (char c : value) {
|
||||
// A canonical integer literal consists only of ASCII decimal digits.
|
||||
if (c < '0' || c > '9') {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return &ctx;
|
||||
}
|
||||
|
||||
IntegerType(StringRef value, bool isNegative, const ASTContext &ctx) :
|
||||
TypeBase(TypeKind::Integer, &ctx, RecursiveTypeProperties()),
|
||||
Value(value) {
|
||||
TypeBase(TypeKind::Integer, getCanonicalIntegerLiteralContext(value, ctx),
|
||||
RecursiveTypeProperties()),
|
||||
Value(value),
|
||||
Context(ctx) {
|
||||
Bits.IntegerType.IsNegative = isNegative;
|
||||
}
|
||||
|
||||
@@ -7917,6 +7934,8 @@ public:
|
||||
static bool classof(const TypeBase *T) {
|
||||
return T->getKind() == TypeKind::Integer;
|
||||
}
|
||||
|
||||
const ASTContext &getASTContext() { return Context; }
|
||||
};
|
||||
DEFINE_EMPTY_CAN_TYPE_WRAPPER(IntegerType, Type)
|
||||
|
||||
|
||||
@@ -3724,8 +3724,9 @@ IntegerType *IntegerType::get(StringRef value, bool isNegative,
|
||||
IntegerType::Profile(id, value, isNegative);
|
||||
|
||||
void *insertPos;
|
||||
if (auto intType = ctx.getImpl().IntegerTypes.FindNodeOrInsertPos(id, insertPos))
|
||||
if (auto intType = ctx.getImpl().IntegerTypes.FindNodeOrInsertPos(id, insertPos)) {
|
||||
return intType;
|
||||
}
|
||||
|
||||
auto strCopy = ctx.AllocateCopy(value);
|
||||
|
||||
|
||||
@@ -6532,6 +6532,7 @@ namespace {
|
||||
printCommon("integer_type", label);
|
||||
printFlag(T->isNegative(), "is_negative");
|
||||
printFieldQuoted(T->getValue(), Label::always("value"), LiteralValueColor);
|
||||
printFieldQuoted(T->getDigitsText(), Label::always("text"), IdentifierColor);
|
||||
printFoot();
|
||||
}
|
||||
|
||||
|
||||
@@ -1878,6 +1878,18 @@ CanType TypeBase::computeCanonicalType() {
|
||||
Result = ErrorUnionType::get(ctx, newTerms).getPointer();
|
||||
break;
|
||||
}
|
||||
case TypeKind::Integer: {
|
||||
auto intTy = cast<IntegerType>(this);
|
||||
APInt value = intTy->getValue();
|
||||
if (intTy->isNegative()) {
|
||||
value = -value;
|
||||
}
|
||||
SmallString<20> canonicalText;
|
||||
value.toStringUnsigned(canonicalText);
|
||||
Result = IntegerType::get(canonicalText, intTy->isNegative(),
|
||||
intTy->getASTContext());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the canonical type for future queries.
|
||||
|
||||
15
test/Sema/integer_generics_spelling.swift
Normal file
15
test/Sema/integer_generics_spelling.swift
Normal file
@@ -0,0 +1,15 @@
|
||||
// RUN: %target-swift-frontend -disable-availability-checking -typecheck -verify %s
|
||||
|
||||
struct Foo<let n: Int> {}
|
||||
|
||||
func foo(x: Foo<256>) {}
|
||||
|
||||
func bar(x: Foo<0x100>) {
|
||||
foo(x: x)
|
||||
}
|
||||
|
||||
func oof(x: Foo<-256>) {}
|
||||
|
||||
func rab(x: Foo<-0x100>) {
|
||||
oof(x: x)
|
||||
}
|
||||
Reference in New Issue
Block a user