forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request swiftlang#34715 from Jumhyn/SR-13815
[Sema] Always look through optionals for unresolved member lookup
- Loading branch information
Showing
9 changed files
with
189 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// RUN: %target-typecheck-verify-swift -dump-ast > %t.dump | ||
// RUN: %FileCheck %s < %t.dump | ||
|
||
// SR-13815 | ||
extension Optional { | ||
func sr13815() -> SR13815? { SR13815() } | ||
static func sr13815_2() -> SR13815? { SR13815() } | ||
static func sr13815_3() -> SR13815? { SR13815() } | ||
static var sr13815_wrongType: Int { 0 } | ||
static var sr13815_overload: SR13815 { SR13815() } | ||
init(overloaded: Void) { self = nil } | ||
} | ||
|
||
struct SR13815 { | ||
static var sr13815: SR13815? = SR13815() | ||
static var sr13815_2: SR13815? = SR13815() | ||
static var sr13815_wrongType: SR13815? { SR13815() } | ||
static var p_SR13815: SR13815? { SR13815() } | ||
static func sr13815_3() -> SR13815? { SR13815() } | ||
static var sr13815_overload: SR13815? { SR13815() } | ||
init(overloaded: Void) {} | ||
init?(failable: Void) {} | ||
init() {} | ||
} | ||
|
||
protocol P_SR13815 {} | ||
extension Optional: P_SR13815 where Wrapped: Equatable { | ||
static func p_SR13815() {} | ||
} | ||
|
||
let _: SR13815? = .sr13815 | ||
let _: SR13815? = .sr13815_wrongType | ||
let _: SR13815? = .init() | ||
let _: SR13815? = .sr13815() // expected-error {{instance member 'sr13815' cannot be used on type 'SR13815?'}} | ||
let _: SR13815? = .sr13815_2() | ||
let _: SR13815? = .init(SR13815()) | ||
let _: SR13815? = .init(overloaded: ()) | ||
// If members exist on Optional and Wrapped, always choose the one on optional | ||
// CHECK: declref_expr {{.*}} location={{.*}}optional_overload.swift:37 | ||
// CHECK-SAME: decl=optional_overload.(file).Optional extension.init(overloaded:) | ||
let _: SR13815? = .sr13815_overload | ||
// Should choose the overload from Optional even if the Wrapped overload would otherwise have a better score | ||
// CHECK: member_ref_expr {{.*}} location={{.*}}optional_overload.swift:41 | ||
// CHECK-SAME: decl=optional_overload.(file).Optional extension.sr13815_overload | ||
let _: SR13815? = .init(failable: ()) | ||
let _: SR13815? = .sr13815_3() | ||
let _: SR13815? = .p_SR13815 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
//===--- UnresolvedMemberLookupTests.cpp --------------------------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "SemaFixture.h" | ||
#include "swift/Sema/ConstraintSystem.h" | ||
|
||
using namespace swift; | ||
using namespace swift::unittest; | ||
using namespace swift::constraints; | ||
|
||
TEST_F(SemaTest, TestLookupAlwaysLooksThroughOptionalBase) { | ||
auto *intTypeDecl = getStdlibNominalTypeDecl("Int"); | ||
auto *optTypeDecl = getStdlibNominalTypeDecl("Optional"); | ||
auto intType = intTypeDecl->getDeclaredType(); | ||
auto intOptType = OptionalType::get(intType); | ||
auto stringType = getStdlibType("String"); | ||
|
||
auto *intMember = addExtensionVarMember(intTypeDecl, "test", intOptType); | ||
addExtensionVarMember(optTypeDecl, "test", stringType); | ||
|
||
auto *UME = new (Context) | ||
UnresolvedMemberExpr(SourceLoc(), DeclNameLoc(), | ||
DeclNameRef(Context.getIdentifier("test")), true); | ||
auto *UMCRE = new (Context) UnresolvedMemberChainResultExpr(UME, UME); | ||
|
||
ConstraintSystem cs(DC, ConstraintSystemOptions()); | ||
cs.generateConstraints(UMCRE, DC); | ||
cs.addConstraint( | ||
ConstraintKind::Conversion, cs.getType(UMCRE), intOptType, | ||
cs.getConstraintLocator(UMCRE, ConstraintLocator::ContextualType)); | ||
SmallVector<Solution, 2> solutions; | ||
cs.solve(solutions); | ||
|
||
// We should have a solution. | ||
ASSERT_EQ(solutions.size(), 1); | ||
|
||
auto &solution = solutions[0]; | ||
auto *locator = cs.getConstraintLocator(UME, | ||
ConstraintLocator::UnresolvedMember); | ||
auto choice = solution.getOverloadChoice(locator).choice; | ||
|
||
// The `test` member on `Int` should be selected. | ||
ASSERT_EQ(choice.getDecl(), intMember); | ||
} | ||
|
||
TEST_F(SemaTest, TestLookupPrefersResultsOnOptionalRatherThanBase) { | ||
auto *intTypeDecl = getStdlibNominalTypeDecl("Int"); | ||
auto *optTypeDecl = getStdlibNominalTypeDecl("Optional"); | ||
auto intType = intTypeDecl->getDeclaredType(); | ||
auto intOptType = OptionalType::get(intType); | ||
|
||
addExtensionVarMember(intTypeDecl, "test", intOptType); | ||
auto *optMember = addExtensionVarMember(optTypeDecl, "test", intType); | ||
|
||
auto *UME = new (Context) | ||
UnresolvedMemberExpr(SourceLoc(), DeclNameLoc(), | ||
DeclNameRef(Context.getIdentifier("test")), true); | ||
auto *UMCRE = new (Context) UnresolvedMemberChainResultExpr(UME, UME); | ||
|
||
ConstraintSystem cs(DC, ConstraintSystemOptions()); | ||
cs.generateConstraints(UMCRE, DC); | ||
cs.addConstraint( | ||
ConstraintKind::Conversion, cs.getType(UMCRE), intOptType, | ||
cs.getConstraintLocator(UMCRE, ConstraintLocator::ContextualType)); | ||
SmallVector<Solution, 2> solutions; | ||
cs.solve(solutions); | ||
|
||
// We should have a solution. | ||
ASSERT_EQ(solutions.size(), 1); | ||
|
||
auto &solution = solutions[0]; | ||
auto *locator = cs.getConstraintLocator(UME, | ||
ConstraintLocator::UnresolvedMember); | ||
auto choice = solution.getOverloadChoice(locator).choice; | ||
auto score = solution.getFixedScore(); | ||
|
||
// The `test` member on `Optional` should be chosen over the member on `Int`, | ||
// even though the score is otherwise worse. | ||
ASSERT_EQ(score.Data[SK_ValueToOptional], 1); | ||
ASSERT_EQ(choice.getDecl(), optMember); | ||
} |