Files
swift-mirror/test/decl/protocol/req/recursion.swift
Slava Pestov 4ed17f0f63 AST: Add a new 'isBeingValidated' flag to replace a couple of other flags
Previously, validateDecl() would check if the declaration had an
interface type and use that as an indication not to proceed.

However for functions we can only set an interface type after
checking the generic signature, so a recursive call to validateDecl()
on a function would "steal" the outer call and complete validation.

For generic types, this meant we could have a declaration with a
valid interface type but no generic signature.

Both cases were problematic, so narrow workarounds were put in
place with additional new flags. This made the code harder to
reason about.

This patch consolidates the flags and establishes new invariants:

- If validateDecl() returns and the declaration has no interface
  type and the isBeingValidated() flag is not set, it means one
  of the parent contexts is being validated by an outer recursive
  call.

- If validateDecl() returns and the declaration has the
  isBeingValidated() flag set, it may or may not have an interface
  type. In this case, the declaration itself is being validated
  by an outer recursive call.

- If validateDecl() returns and the declaration has an interface
  type and the isBeingValidated() flag is not set, it means the
  declaration and all of its parent contexts are fully validated
  and ready for use.

In general, we still want name lookup to find things that have an
interface type but are not in a valid generic context, so for this
reason nominal types and associated types get an interface type as
early as possible.

Most other code only wants to see fully formed decls, so a new
hasValidSignature() method returns true iff the interface type is
set and the isBeingValidated() flag is not set.

For example, while resolving a type, we can resolve an unqualified
reference to a nominal type without a valid signature. However, when
applying generic parameters, the hasValidSignature() flag is used
to ensure we error out instead of crashing if the generic signature
has not yet been formed.
2016-12-19 01:38:23 -08:00

110 lines
3.3 KiB
Swift

// RUN: %target-typecheck-verify-swift
protocol SomeProtocol {
associatedtype T
}
extension SomeProtocol where T == Optional<T> { } // expected-error{{same-type constraint 'Self.T' == 'Optional<Self.T>' is recursive}}
// rdar://problem/19840527
class X<T> where T == X { // expected-error{{same-type constraint 'T' == 'X<T>' is recursive}}
// expected-error@-1{{same-type requirement makes generic parameter 'T' non-generic}}
// expected-error@-2{{same-type requirement makes generic parameter 'T' non-generic}}
var type: T { return type(of: self) }
}
// FIXME: The "associated type 'Foo' is not a member type of 'Self'" diagnostic
// should also become "associated type 'Foo' references itself"
protocol CircularAssocTypeDefault {
associatedtype Z = Z // expected-error{{associated type 'Z' references itself}}
// expected-note@-1{{type declared here}}
// expected-note@-2{{protocol requires nested type 'Z'; do you want to add it?}}
associatedtype Z2 = Z3 // expected-note{{type declared here}}
// expected-note@-1{{protocol requires nested type 'Z2'; do you want to add it?}}
associatedtype Z3 = Z2 // expected-error{{associated type 'Z2' references itself}}
// expected-note@-1{{protocol requires nested type 'Z3'; do you want to add it?}}
associatedtype Z4 = Self.Z4 // expected-error{{associated type 'Z4' is not a member type of 'Self'}}
// expected-note@-1{{protocol requires nested type 'Z4'; do you want to add it?}}
associatedtype Z5 = Self.Z6
// expected-note@-1{{protocol requires nested type 'Z5'; do you want to add it?}}
associatedtype Z6 = Self.Z5 // expected-error{{associated type 'Z5' is not a member type of 'Self'}}
// expected-note@-1{{protocol requires nested type 'Z6'; do you want to add it?}}
}
struct ConformsToCircularAssocTypeDefault : CircularAssocTypeDefault { }
// expected-error@-1 {{type 'ConformsToCircularAssocTypeDefault' does not conform to protocol 'CircularAssocTypeDefault'}}
// rdar://problem/20000145
public protocol P {
associatedtype T
}
public struct S<A: P> where A.T == S<A> {
// expected-note@-1 {{type declared here}}
// expected-error@-2 {{generic struct 'S' references itself}}
func f(a: A.T) {
g(a: id(t: a))
// expected-error@-1 {{cannot convert value of type 'A.T' to expected argument type 'S<_>'}}
_ = A.T.self
}
func g(a: S<A>) {
f(a: id(t: a))
// expected-note@-1 {{expected an argument list of type '(a: A.T)'}}
// expected-error@-2 {{cannot invoke 'f' with an argument list of type '(a: S<A>)'}}
_ = S<A>.self
}
func id<T>(t: T) -> T {
return t
}
}
protocol I {
// FIXME: these are spurious
init() // expected-note {{protocol requires initializer 'init()' with type '()'}}
}
protocol PI {
associatedtype T : I
}
struct SI<A: PI> : I where A : I, A.T == SI<A> {
// expected-note@-1 {{type declared here}}
// expected-error@-2 {{generic struct 'SI' references itself}}
func ggg<T : I>(t: T.Type) -> T {
return T()
}
func foo() {
_ = A()
_ = A.T()
_ = SI<A>()
_ = ggg(t: A.self)
_ = ggg(t: A.T.self)
_ = self.ggg(t: A.self)
_ = self.ggg(t: A.T.self)
}
}
// Used to hit infinite recursion
struct S4<A: PI> : I where A : I {
}
struct S5<A: PI> : I where A : I, A.T == S4<A> {
}
// Used to hit ArchetypeBuilder assertions
struct SU<A: P> where A.T == SU {
}
struct SIU<A: PI> : I where A : I, A.T == SIU {
}