Skip to content

Commit ccc0a89

Browse files
authored
Merge pull request #25956 from jckarter/opaque-stored-properties
Support opaque stored property types.
2 parents 064c791 + 09f8296 commit ccc0a89

File tree

6 files changed

+73
-9
lines changed

6 files changed

+73
-9
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3332,6 +3332,9 @@ ERROR(trailing_closure_requires_parens,none,
33323332
"trailing closure requires parentheses for disambiguation in this"
33333333
" context", ())
33343334

3335+
ERROR(opaque_type_var_no_init,none,
3336+
"property declares an opaque return type, but has no initializer "
3337+
"expression from which to infer an underlying type", ())
33353338
ERROR(opaque_type_no_underlying_type_candidates,none,
33363339
"function declares an opaque return type, but has no return statements "
33373340
"in its body from which to infer an underlying type", ())
@@ -3343,6 +3346,9 @@ NOTE(opaque_type_underlying_type_candidate_here,none,
33433346
ERROR(opaque_type_self_referential_underlying_type,none,
33443347
"function opaque return type was inferred as %0, which defines the "
33453348
"opaque type in terms of itself", (Type))
3349+
ERROR(opaque_type_var_no_underlying_type,none,
3350+
"property declares an opaque return type, but cannot infer the "
3351+
"underlying type from its initializer expression", ())
33463352

33473353
//------------------------------------------------------------------------------
33483354
// MARK: Type Check Patterns

lib/Sema/CSSolver.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,8 @@ ConstraintSystem::solveImpl(Expr *&expr,
12081208
auto constraintKind = ConstraintKind::Conversion;
12091209

12101210
if ((getContextualTypePurpose() == CTP_ReturnStmt ||
1211-
getContextualTypePurpose() == CTP_ReturnSingleExpr)
1211+
getContextualTypePurpose() == CTP_ReturnSingleExpr ||
1212+
getContextualTypePurpose() == CTP_Initialization)
12121213
&& Options.contains(ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType))
12131214
constraintKind = ConstraintKind::OpaqueUnderlyingType;
12141215

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,8 +2649,11 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
26492649
initType = patternType;
26502650

26512651
// Add a conversion constraint between the types.
2652-
cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
2653-
patternType, Locator, /*isFavored*/true);
2652+
if (!cs.Options.contains(
2653+
ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType)) {
2654+
cs.addConstraint(ConstraintKind::Conversion, cs.getType(expr),
2655+
patternType, Locator, /*isFavored*/true);
2656+
}
26542657
}
26552658

26562659
// The expression has been pre-checked; save it in case we fail later.
@@ -2762,6 +2765,13 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
27622765
// If we already had an error, don't repeat the problem.
27632766
if (contextualType.getType()->hasError())
27642767
return true;
2768+
2769+
// Allow the initializer expression to establish the underlying type of an
2770+
// opaque type.
2771+
if (auto opaqueType = pattern->getType()->getAs<OpaqueTypeArchetypeType>()){
2772+
flags |= TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType;
2773+
flags -= TypeCheckExprFlags::ConvertTypeIsOnlyAHint;
2774+
}
27652775

27662776
// Only provide a TypeLoc if it makes sense to allow diagnostics.
27672777
if (auto *typedPattern = dyn_cast<TypedPattern>(pattern)) {
@@ -2846,10 +2856,35 @@ bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
28462856
PBD->setPattern(patternNumber, pattern, initContext);
28472857
PBD->setInit(patternNumber, init);
28482858

2859+
// Bind a property with an opaque return type to the underlying type
2860+
// given by the initializer.
2861+
if (auto var = pattern->getSingleVar()) {
2862+
if (auto opaque = var->getOpaqueResultTypeDecl()) {
2863+
if (auto convertedInit = dyn_cast<UnderlyingToOpaqueExpr>(init)) {
2864+
auto underlyingType = convertedInit->getSubExpr()->getType()
2865+
->mapTypeOutOfContext();
2866+
auto underlyingSubs = SubstitutionMap::get(
2867+
opaque->getOpaqueInterfaceGenericSignature(),
2868+
[&](SubstitutableType *t) -> Type {
2869+
if (t->isEqual(opaque->getUnderlyingInterfaceType())) {
2870+
return underlyingType;
2871+
}
2872+
return Type(t);
2873+
},
2874+
LookUpConformanceInModule(opaque->getModuleContext()));
2875+
2876+
opaque->setUnderlyingTypeSubstitutions(underlyingSubs);
2877+
} else {
2878+
diagnose(var->getLoc(), diag::opaque_type_var_no_underlying_type);
2879+
}
2880+
}
2881+
}
2882+
28492883
if (hadError)
28502884
PBD->setInvalid();
28512885

28522886
PBD->setInitializerChecked(patternNumber);
2887+
28532888
return hadError;
28542889
}
28552890

lib/Sema/TypeCheckDecl.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2535,6 +2535,12 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25352535
if (!var->hasType())
25362536
var->markInvalid();
25372537
};
2538+
2539+
// Properties with an opaque return type need an initializer to
2540+
// determine their underlying type.
2541+
if (var->getOpaqueResultTypeDecl()) {
2542+
TC.diagnose(var->getLoc(), diag::opaque_type_var_no_init);
2543+
}
25382544

25392545
// Non-member observing properties need an initializer.
25402546
if (var->getWriteImpl() == WriteImplKind::StoredWithObservers &&
@@ -2593,8 +2599,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25932599
if (!PBD->isInitialized(i))
25942600
continue;
25952601

2596-
if (!PBD->isInitializerChecked(i))
2602+
if (!PBD->isInitializerChecked(i)) {
25972603
TC.typeCheckPatternBinding(PBD, i);
2604+
}
25982605

25992606
if (!PBD->isInvalid()) {
26002607
auto &entry = PBD->getPatternList()[i];

test/IRGen/opaque_result_type.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,9 @@ struct X<T: R, U: R>: R {
192192
}
193193
}
194194

195+
var globalOProp: some O = 0
196+
197+
struct OpaqueProps {
198+
static var staticOProp: some O = 0
199+
var instanceOProp: some O = 0
200+
}

test/type/opaque.swift

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ extension Array: P, Q { func paul() {}; mutating func priscilla() {}; func quinn
1212
class C {}
1313
class D: C, P, Q { func paul() {}; func priscilla() {}; func quinn() {} }
1414

15-
// TODO: Should be valid
16-
17-
let property: some P = 1 // TODO expected-error{{cannot convert}}
18-
let deflessProperty: some P // TODO e/xpected-error{{butz}}
15+
let property: some P = 1
16+
let deflessLet: some P // expected-error{{has no initializer}}
17+
var deflessVar: some P // expected-error{{has no initializer}}
1918

2019
struct GenericProperty<T: P> {
2120
var x: T
@@ -159,7 +158,6 @@ func typeIdentity() {
159158

160159
// The opaque type should expose the members implied by its protocol
161160
// constraints
162-
// TODO: associated types
163161
do {
164162
var a = alice()
165163
a.paul()
@@ -404,3 +402,14 @@ func testCoercionDiagnostics() {
404402
opaqueOpt = bar() // expected-error {{cannot assign value of type 'some P' to type '(some P)?'}} {{none}}
405403
opaqueOpt = () // expected-error {{cannot assign value of type '()' to type '(some P)?'}} {{none}}
406404
}
405+
406+
var globalVar: some P = 17
407+
let globalLet: some P = 38
408+
409+
struct Foo {
410+
static var staticVar: some P = 17
411+
static let staticLet: some P = 38
412+
413+
var instanceVar: some P = 17
414+
let instanceLet: some P = 38
415+
}

0 commit comments

Comments
 (0)