Skip to content

Commit 8f55238

Browse files
committed
[TypeChecker] Fix a crash in inherited default argument type-checking
In some circumstances request for default type is made before inherited constructor has been validated and storage has been allocated for invalid type which then triggered a crash during declaration checking.
1 parent d727a79 commit 8f55238

File tree

3 files changed

+44
-3
lines changed

3 files changed

+44
-3
lines changed

lib/AST/Decl.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7099,12 +7099,19 @@ void ParamDecl::setDefaultExpr(Expr *E, bool isTypeChecked) {
70997099
"Can't overwrite type-checked default with un-type-checked default");
71007100
}
71017101
defaultInfo->DefaultArg = E;
7102-
defaultInfo->ExprType = E->getType();
7102+
// `Inherited` default arguments do not have an expression,
7103+
// so if the storage has been pre-allocated already we need
7104+
// to be careful requesting type here.
7105+
defaultInfo->ExprType = E ? E->getType() : Type();
71037106
defaultInfo->InitContextAndIsTypeChecked.setInt(isTypeChecked);
71047107
}
71057108

71067109
void ParamDecl::setDefaultExprType(Type type) {
71077110
if (!DefaultValueAndFlags.getPointer()) {
7111+
// If there is no type, let's not allocate storage.
7112+
if (!type)
7113+
return;
7114+
71087115
DefaultValueAndFlags.setPointer(
71097116
getASTContext().Allocate<StoredDefaultArgument>());
71107117
}

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,8 +1065,10 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator,
10651065

10661066
Type DefaultArgumentTypeRequest::evaluate(Evaluator &evaluator,
10671067
ParamDecl *param) const {
1068-
if (auto expr = param->getTypeCheckedDefaultExpr())
1069-
return expr->getType();
1068+
if (auto *expr = param->getTypeCheckedDefaultExpr()) {
1069+
// If the request failed, let's not propagate ErrorType up.
1070+
return isa<ErrorExpr>(expr) ? Type() : expr->getType();
1071+
}
10701072
return Type();
10711073
}
10721074

test/Constraints/type_inference_from_default_exprs.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,35 @@ func test_allow_same_type_between_dependent_types() {
199199
s.test() // expected-error {{instance method 'test' requires the types 'String' and 'Default.X' (aka 'Int') be equivalent}}
200200
}
201201
}
202+
203+
// Crash when default type is requested before inherited constructor is type-checked
204+
205+
protocol StorageType {
206+
var identifier: String { get }
207+
}
208+
209+
class Storage {
210+
}
211+
212+
extension Storage {
213+
struct Test {
214+
static let test = CustomStorage<String>("") // triggers default type request
215+
}
216+
}
217+
218+
class BaseStorage<T> : Storage, StorageType {
219+
enum StorageType {
220+
case standard
221+
}
222+
223+
let identifier: String
224+
let type: StorageType
225+
226+
init(_ id: String, type: StorageType = .standard) {
227+
self.identifier = id
228+
self.type = type
229+
}
230+
}
231+
232+
final class CustomStorage<T>: BaseStorage<T> { // Ok - no crash typechecking inherited init
233+
}

0 commit comments

Comments
 (0)