Skip to content

Improve warning for inferring an undesirable type #27797

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions lib/Sema/TypeCheckPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -978,12 +978,10 @@ bool TypeChecker::coercePatternToType(Pattern *&P, TypeResolution resolution,
TypeChecker::checkForForbiddenPrefix(Context, var->getBaseName());

// If we are inferring a variable to have type AnyObject.Type,
// "()", an uninhabited type, or optional thereof, emit a diagnostic.
// In the first 2 cases, the coder probably forgot a cast and expected a
// concrete type. In the later case, they probably didn't mean to bind to
// a variable, or there is some other bug. We always tell them that they
// can silence the warning with an explicit type annotation
// (and provide a fixit) as a note.
// "()", "[()]", an uninhabited type, or optional thereof, emit a diagnostic.
// They are probably missing a cast or didn't mean to bind to a variable.
// We always tell them that they can silence the warning with an
// explicit type annotation (and provide a fixit) as a note.
Type diagTy = type->lookThroughAllOptionalTypes();
bool isOptional = !type->getOptionalObjectType().isNull();
if (!diagTy) diagTy = type;
Expand All @@ -1010,6 +1008,9 @@ bool TypeChecker::coercePatternToType(Pattern *&P, TypeResolution resolution,
assert((diagTy->is<EnumType>() || diagTy->is<BoundGenericEnumType>()) &&
"unknown structurally uninhabited type");
}
} else if (auto *BST = diagTy->getAs<BoundGenericStructType>()) {
if (BST->getDecl() == Context.getArrayDecl())
shouldRequireType = BST->getGenericArgs()[0]->isEqual(Context.TheEmptyTupleType);
}

if (shouldRequireType &&
Expand All @@ -1018,8 +1019,8 @@ bool TypeChecker::coercePatternToType(Pattern *&P, TypeResolution resolution,
!(options & TypeResolutionFlags::FromNonInferredPattern)) {
diags.diagnose(NP->getLoc(), diag, NP->getDecl()->getName(), type,
NP->getDecl()->isLet());
diags.diagnose(NP->getLoc(),
diag::add_explicit_type_annotation_to_silence);
diags.diagnose(NP->getLoc(), diag::add_explicit_type_annotation_to_silence)
.fixItInsertAfter(var->getNameLoc(), ": " + type->getWithoutParens()->getString());
}

return false;
Expand Down
24 changes: 24 additions & 0 deletions test/SourceKit/Sema/placeholders.swift.placeholders.response
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,29 @@
key.length: 9
}
]
},
{
key.line: 8,
key.column: 5,
key.filepath: placeholders.swift,
key.severity: source.diagnostic.severity.warning,
key.description: "constant 'myArray' inferred to have type '[()]', which may be unexpected",
key.diagnostic_stage: source.diagnostic.stage.swift.sema,
key.diagnostics: [
{
key.line: 8,
key.column: 5,
key.filepath: placeholders.swift,
key.severity: source.diagnostic.severity.note,
key.description: "add an explicit type annotation to silence this warning",
key.fixits: [
{
key.offset: 236,
key.length: 0,
key.sourcetext: ": [()]"
}
]
}
]
}
]
2 changes: 1 addition & 1 deletion test/decl/var/lazy_properties.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ struct Outer {

lazy var y = {_ = 3}()
// expected-warning@-1 {{variable 'y' inferred to have type '()', which may be unexpected}}
// expected-note@-2 {{add an explicit type annotation to silence this warning}}
// expected-note@-2 {{add an explicit type annotation to silence this warning}} {{15-15=: ()}}
}
}

Expand Down
10 changes: 5 additions & 5 deletions test/decl/var/properties.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1272,11 +1272,11 @@ class WeakFixItTest {

// SR-8811 (Warning)

let sr8811a = fatalError() // expected-warning {{constant 'sr8811a' inferred to have type 'Never', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}}
let sr8811a = fatalError() // expected-warning {{constant 'sr8811a' inferred to have type 'Never', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}} {{12-12=: Never}}

let sr8811b: Never = fatalError() // Ok

let sr8811c = (16, fatalError()) // expected-warning {{constant 'sr8811c' inferred to have type '(Int, Never)', which contains an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}}
let sr8811c = (16, fatalError()) // expected-warning {{constant 'sr8811c' inferred to have type '(Int, Never)', which contains an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}} {{12-12=: (Int, Never)}}

let sr8811d: (Int, Never) = (16, fatalError()) // Ok

Expand All @@ -1292,11 +1292,11 @@ class SR_10995 {
}

func sr_10995_foo() {
let doubleOptionalNever = makeDoubleOptionalNever() // expected-warning {{constant 'doubleOptionalNever' inferred to have type 'Never??', which may be unexpected}}
// expected-note@-1 {{add an explicit type annotation to silence this warning}}
let doubleOptionalNever = makeDoubleOptionalNever() // expected-warning {{constant 'doubleOptionalNever' inferred to have type 'Never??', which may be unexpected}}
// expected-note@-1 {{add an explicit type annotation to silence this warning}} {{28-28=: Never??}}
// expected-warning@-2 {{initialization of immutable value 'doubleOptionalNever' was never used; consider replacing with assignment to '_' or removing it}}
let singleOptionalNever = makeSingleOptionalNever() // expected-warning {{constant 'singleOptionalNever' inferred to have type 'Never?', which may be unexpected}}
// expected-note@-1 {{add an explicit type annotation to silence this warning}}
// expected-note@-1 {{add an explicit type annotation to silence this warning}} {{28-28=: Never?}}
// expected-warning@-2 {{initialization of immutable value 'singleOptionalNever' was never used; consider replacing with assignment to '_' or removing it}}
}
}
Expand Down
14 changes: 12 additions & 2 deletions test/decl/var/variables.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ struct Broken {

// rdar://16252090 - Warning when inferring empty tuple type for declarations
var emptyTuple = testShadowing() // expected-warning {{variable 'emptyTuple' inferred to have type '()'}} \
// expected-note {{add an explicit type annotation to silence this warning}}
// expected-note {{add an explicit type annotation to silence this warning}} {{15-15=: ()}}

// rdar://15263687 - Diagnose variables inferenced to 'AnyObject'
var ao1 : AnyObject
var ao2 = ao1

var aot1 : AnyObject.Type
var aot2 = aot1 // expected-warning {{variable 'aot2' inferred to have type 'AnyObject.Type', which may be unexpected}} \
// expected-note {{add an explicit type annotation to silence this warning}}
// expected-note {{add an explicit type annotation to silence this warning}} {{9-9=: AnyObject.Type}}


for item in [AnyObject]() { // No warning in for-each loop.
Expand All @@ -60,6 +60,16 @@ func testAnyObjectOptional() -> AnyObject? {
return x
}

// SR-11511 Warning for inferring an array of empty tuples
var arrayOfEmptyTuples = [""].map { print($0) } // expected-warning {{variable 'arrayOfEmptyTuples' inferred to have type '[()]'}} \
// expected-note {{add an explicit type annotation to silence this warning}} {{23-23=: [()]}}

var maybeEmpty = Optional(arrayOfEmptyTuples) // expected-warning {{variable 'maybeEmpty' inferred to have type '[()]?'}} \
// expected-note {{add an explicit type annotation to silence this warning}} {{15-15=: [()]?}}

var shouldWarnWithoutSugar = (arrayOfEmptyTuples as Array<()>) // expected-warning {{variable 'shouldWarnWithoutSugar' inferred to have type 'Array<()>'}} \
// expected-note {{add an explicit type annotation to silence this warning}} {{27-27=: Array<()>}}

class SomeClass {}

// <rdar://problem/16877304> weak let's should be rejected
Expand Down
4 changes: 2 additions & 2 deletions test/expr/expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -588,9 +588,9 @@ func conversionTest(_ a: inout Double, b: inout Int) {
var pi_f3 = float.init(getPi()) // expected-error {{ambiguous use of 'init(_:)'}}
var pi_f4 = float.init(pi_f)

var e = Empty(f) // expected-warning {{variable 'e' inferred to have type 'Empty', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}}
var e = Empty(f) // expected-warning {{variable 'e' inferred to have type 'Empty', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}} {{8-8=: Empty}}
var e2 = Empty(d) // expected-error{{cannot convert value of type 'Double' to expected argument type 'Float'}}
var e3 = Empty(Float(d)) // expected-warning {{variable 'e3' inferred to have type 'Empty', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}}
var e3 = Empty(Float(d)) // expected-warning {{variable 'e3' inferred to have type 'Empty', which is an enum with no cases}} expected-note {{add an explicit type annotation to silence this warning}} {{9-9=: Empty}}
}

struct Rule {
Expand Down