Skip to content

Commit 3daae59

Browse files
committed
[AST] Use ErrorType for invalid value generic parameter
If we fail to resolve the value type for a value generic parameter, previously we would have returned a null Type, causing crashes downstream. Instead, return an ErrorType, leaving a null Type for cases where the generic parameter isn't a value generic at all. rdar://154856417
1 parent 1bd32a1 commit 3daae59

File tree

7 files changed

+29
-21
lines changed

7 files changed

+29
-21
lines changed

lib/AST/Decl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6121,9 +6121,13 @@ GenericTypeParamDecl *GenericTypeParamDecl::createImplicit(
61216121
}
61226122

61236123
Type GenericTypeParamDecl::getValueType() const {
6124-
return evaluateOrDefault(getASTContext().evaluator,
6125-
GenericTypeParamDeclGetValueTypeRequest{this},
6126-
Type());
6124+
if (!isValue())
6125+
return Type();
6126+
6127+
auto &ctx = getASTContext();
6128+
GenericTypeParamDeclGetValueTypeRequest req(this);
6129+
auto ty = evaluateOrDefault(ctx.evaluator, req, Type());
6130+
return ty ? ty : ErrorType::get(ctx);
61276131
}
61286132

61296133
SourceRange GenericTypeParamDecl::getSourceRange() const {

lib/Sema/CSGen.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1745,7 +1745,10 @@ namespace {
17451745
}
17461746

17471747
Type visitTypeValueExpr(TypeValueExpr *E) {
1748-
return E->getParamDecl()->getValueType();
1748+
auto ty = E->getParamDecl()->getValueType();
1749+
if (!ty || ty->hasError())
1750+
return recordInvalidNode(E);
1751+
return ty;
17491752
}
17501753

17511754
Type visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *expr) {

lib/Sema/TypeCheckRequestFunctions.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,10 +488,10 @@ Type ResultBuilderTypeRequest::evaluate(Evaluator &evaluator,
488488

489489
Type GenericTypeParamDeclGetValueTypeRequest::evaluate(
490490
Evaluator &evaluator, const GenericTypeParamDecl *decl) const {
491-
if (!decl->isValue())
492-
return Type();
491+
ASSERT(decl->isValue());
493492

494-
if (decl->getInherited().size() == 0) {
493+
auto inherited = decl->getInherited();
494+
if (inherited.empty()) {
495495
decl->diagnose(diag::missing_value_generic_type, decl->getName());
496496
return Type();
497497
}
@@ -502,12 +502,11 @@ Type GenericTypeParamDeclGetValueTypeRequest::evaluate(
502502
//
503503
// We should have 1 inherited type for 'N', 'Int', and have a 2nd generic
504504
// parameter called 'Bool'.
505-
ASSERT(decl->getInherited().size() == 1);
505+
ASSERT(inherited.size() == 1);
506506

507507
// The value type of a generic parameter should never rely on the generic
508508
// signature of the generic parameter itself or any of the outside context.
509-
return decl->getInherited().getResolvedType(0,
510-
TypeResolutionStage::Structural);
509+
return inherited.getResolvedType(0, TypeResolutionStage::Structural);
511510
}
512511

513512
// Define request evaluation functions for each of the type checker requests.

lib/Sema/TypeCheckType.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -808,16 +808,16 @@ namespace {
808808
if (!paramType->isValue())
809809
return true;
810810

811-
// Both of these generic type parameters are values, but they may not have
812-
// underlying value types associated with them. This can occur when a
813-
// parameter doesn't declare a value type and we're going to diagnose it
814-
// later.
815-
if (!paramType->getValueType() || !secondType->getValueType())
811+
// If either value type has an error, we've already diagnosed the issue.
812+
auto paramValueTy = paramType->getValueType();
813+
auto secondValueTy = secondType->getValueType();
814+
if (!paramValueTy || paramValueTy->hasError() ||
815+
!secondValueTy || secondValueTy->hasError()) {
816816
return true;
817-
817+
}
818818
// Otherwise, these are both value parameters and check that both their
819819
// value types are the same.
820-
return paramType->getValueType()->isEqual(secondType->getValueType());
820+
return paramValueTy->isEqual(secondValueTy);
821821
}
822822

823823
bool alwaysMismatchTypeParameters() const { return true; }

test/Sema/value_generics.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
protocol P {}
44

5-
func invalid<let N>() {} // expected-error {{value generic 'N' must have an explicit value type declared}}
6-
// expected-error@-1 {{generic parameter 'N' is not used in function signature}}
5+
func invalid<let N>() { // expected-error {{value generic 'N' must have an explicit value type declared}}
6+
// expected-error@-1 {{generic parameter 'N' is not used in function signature}}
7+
let x: String = N // Fine, we bind to a hole.
8+
}
79
func invalid<let N>(_: A<N>) {} // expected-error {{value generic 'N' must have an explicit value type declared}}
810

911
struct A<let N: Int> {
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// {"kind":"complete","signature":"swift::Mangle::ASTMangler::appendType(swift::Type, swift::GenericSignature, swift::ValueDecl const*)"}
2-
// RUN: not --crash %target-swift-ide-test -code-completion --code-completion-token=COMPLETE -source-filename %s
2+
// RUN: %target-swift-ide-test -code-completion --code-completion-token=COMPLETE -source-filename %s
33
func a<let b
44
#^COMPLETE^#

validation-test/compiler_crashers_2/c232a2df5b6fffd.swift renamed to validation-test/compiler_crashers_2_fixed/c232a2df5b6fffd.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// {"signature":"swift::constraints::ConstraintSystem::getTypeOfMemberReference(swift::Type, swift::ValueDecl*, swift::DeclContext*, bool, swift::FunctionRefInfo, swift::constraints::ConstraintLocator*, llvm::SmallVectorImpl<std::__1::pair<swift::GenericTypeParamType*, swift::TypeVariableType*>>*)"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
2+
// RUN: not %target-swift-frontend -typecheck %s
33
struct a < let b > {
44
func
55
< (c : Self) {

0 commit comments

Comments
 (0)