Skip to content

[5.5][Serialization] Do not assert when inherited type is null #37476

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
May 20, 2021
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
20 changes: 9 additions & 11 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3066,10 +3066,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {

SmallVector<TypeID, 8> inheritedAndDependencyTypes;
for (auto inherited : extension->getInherited()) {
if (extension->getASTContext().LangOpts.AllowModuleWithCompilerErrors &&
!inherited.getType())
continue;
assert(!inherited.getType()->hasArchetype());
assert(!inherited.getType() || !inherited.getType()->hasArchetype());
inheritedAndDependencyTypes.push_back(S.addTypeRef(inherited.getType()));
}
size_t numInherited = inheritedAndDependencyTypes.size();
Expand Down Expand Up @@ -3307,7 +3304,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {

SmallVector<TypeID, 4> inheritedAndDependencyTypes;
for (auto inherited : theStruct->getInherited()) {
assert(!inherited.getType()->hasArchetype());
assert(!inherited.getType() || !inherited.getType()->hasArchetype());
inheritedAndDependencyTypes.push_back(S.addTypeRef(inherited.getType()));
}

Expand Down Expand Up @@ -3352,7 +3349,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {

SmallVector<TypeID, 4> inheritedAndDependencyTypes;
for (auto inherited : theEnum->getInherited()) {
assert(!inherited.getType()->hasArchetype());
assert(!inherited.getType() || !inherited.getType()->hasArchetype());
inheritedAndDependencyTypes.push_back(S.addTypeRef(inherited.getType()));
}

Expand Down Expand Up @@ -3410,7 +3407,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {

SmallVector<TypeID, 4> inheritedAndDependencyTypes;
for (auto inherited : theClass->getInherited()) {
assert(!inherited.getType()->hasArchetype());
assert(!inherited.getType() || !inherited.getType()->hasArchetype());
inheritedAndDependencyTypes.push_back(S.addTypeRef(inherited.getType()));
}

Expand Down Expand Up @@ -3468,10 +3465,11 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
llvm::SmallSetVector<Type, 4> dependencyTypes;

for (auto element : proto->getInherited()) {
assert(!element.getType()->hasArchetype());
inheritedAndDependencyTypes.push_back(S.addTypeRef(element.getType()));
if (element.getType()->is<ProtocolType>())
dependencyTypes.insert(element.getType());
auto elementType = element.getType();
assert(!elementType || !elementType->hasArchetype());
inheritedAndDependencyTypes.push_back(S.addTypeRef(elementType));
if (elementType && elementType->is<ProtocolType>())
dependencyTypes.insert(elementType);
}

for (Requirement req : proto->getRequirementSignature()) {
Expand Down
127 changes: 6 additions & 121 deletions test/Frontend/allow-errors.swift
Original file line number Diff line number Diff line change
@@ -1,126 +1,11 @@
// RUN: %empty-directory(%t)

// The module should be generated regardless of errors and diagnostic should still be output
// RUN: %target-swift-frontend -verify -emit-module -o %t/errors.swiftmodule -emit-reference-dependencies-path %t/errors.swiftdeps -emit-dependencies-path %t/errors.d -experimental-allow-module-with-compiler-errors -D ERROR_MODULE -primary-file %s
// The module should be generated regardless of errors, including .swiftdeps, .d,
// .swiftsourceinfo, etc. Diagnostics should still be output as well

// RUN: %target-swift-frontend -verify -emit-module -o %t/errors.swiftmodule -emit-module-source-info -emit-module-doc -emit-reference-dependencies-path %t/errors.swiftdeps -emit-dependencies-path %t/errors.d -experimental-allow-module-with-compiler-errors -primary-file %s
// RUN: llvm-bcanalyzer %t/errors.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
// RUN: ls %t/errors.swiftdeps %t/errors.d %t/errors.swiftsourceinfo %t/errors.swiftdoc
// CHECK-BC-NOT: UnknownCode
// RUN: ls %t/errors.swiftdeps
// RUN: ls %t/errors.d

#if ERROR_MODULE
public struct ValidStructInvalidMember {
public var member: String
public let memberMissingType: undefined // expected-error {{cannot find type 'undefined'}}

public var memberMissingTypeValidSets: undefined { // expected-error {{cannot find type 'undefined'}}
willSet {
print("Setting value \(newValue)")
}
didSet {
print("Set value \(oldValue)")
}
}
public var memberInvalidSets: Int {
willSet {
undefined // expected-error {{cannot find 'undefined'}}
}
didSet {
undefined // expected-error {{cannot find 'undefined'}}
}
}

public lazy var lazyMemberMissingTypeValidBody: undefined = { // expected-error {{cannot find type 'undefined'}}
return ""
}()
public lazy var lazyMemberInvalidBody: String = {
return undefined // expected-error {{cannot find 'undefined'}}
}()

public var memberMissingTypeValidGetSets: String {
get { member }
set { member = "" }
}
public var memberInvalidGetSet: String {
get { undefined } // expected-error {{cannot find 'undefined'}}
set { undefined = "" } // expected-error {{cannot find 'undefined'}}
}

public func funcBadArg(_ arg: undefined? = nil) {} // expected-error {{cannot find type 'undefined'}}
}

public func validFunc() -> String { "" }

public func invalidFuncBody() -> ValidStructInvalidMember {
ret // expected-error {{cannot find 'ret'}}
}

public func invalidFunc() -> undefined {} // expected-error {{cannot find type 'undefined'}}

extension undefined: undefined {} // expected-error {{cannot find type 'undefined'}}

class GenericClass<T> {}
class InvalidSuperclass: GenericClass<undefined> {} // expected-error {{cannot find type 'undefined'}}
#endif

// RUN: %target-swift-frontend -emit-module -o %t/validUses.swiftmodule -experimental-allow-module-with-compiler-errors -I%t -D VALID_USES %s 2>&1 | %FileCheck -check-prefix=CHECK-VALID %s
// RUN: llvm-bcanalyzer %t/validUses.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
#if VALID_USES
import errors
func test(s: ValidStructInvalidMember) {
print(s.member)
print(validFunc())
print(invalidFuncBody())
}

// Check SIL diagnostics are still output (no reason not to output SIL since
// there were no errors)
func other() -> Int {}
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:22: error: missing return in a function expected to return 'Int'
func other2() -> Bool {}
// CHECK-VALID: allow-errors.swift:[[@LINE-1]]:24: error: missing return in a function expected to return 'Bool'
#endif

// All invalid uses should have no errors in the file itself, all referenced
// invalid declarations should have an error elsewhere (but we don't care what
// that location is)

// RUN: %target-swift-frontend -emit-module -o %t/invalidTopUse.swiftmodule -experimental-allow-module-with-compiler-errors -I%t -D INVALID_TOP_LEVEL_USE %s 2>&1 | %FileCheck -check-prefix=CHECK-INVALID-TOP %s
// RUN: llvm-bcanalyzer %t/invalidTopUse.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
#if INVALID_TOP_LEVEL_USE
import errors
func test() {
invalidFunc()
}
// CHECK-INVALID-TOP-NOT: allow-errors.swift:{{.*}} error:
// CHECK-INVALID-TOP: error: allowing deserialization of error type '<null>' in module 'errors'
// CHECK-INVALID-TOP: error: allowing deserialization of invalid declaration 'invalidFunc()' (global function) in module 'errors'
// CHECK-INVALID-TOP-NOT: allow-errors.swift:{{.*}} error:
#endif

// RUN: %target-swift-frontend -emit-module -o %t/invalidMemberUse.swiftmodule -experimental-allow-module-with-compiler-errors -I%t -D INVALID_MEMBER_USE %s 2>&1 | %FileCheck -check-prefix=CHECK-INVALID-MEMBER %s
// RUN: llvm-bcanalyzer %t/invalidMemberUse.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
#if INVALID_MEMBER_USE
import errors
func test(s: ValidStructInvalidMember) {
print(s.memberMissingType)
}
// CHECK-INVALID-MEMBER-NOT: allow-errors.swift:{{.*}} error:
// CHECK-INVALID-MEMBER: error: allowing deserialization of error type '<null>' in module 'errors'
// CHECK-INVALID-MEMBER: error: allowing deserialization of invalid declaration '_' (getter) in module 'errors'
// CHECK-INVALID-MEMBER: error: allowing deserialization of invalid declaration 'memberMissingType' (property) in module 'errors'
// CHECK-INVALID-MEMBER-NOT: allow-errors.swift:{{.*}} error:
#endif

// RUN: %target-swift-frontend -emit-module -o %t/invalidMethodUse.swiftmodule -experimental-allow-module-with-compiler-errors -I%t -D INVALID_METHOD_USE %s 2>&1 | %FileCheck -check-prefix=CHECK-INVALID-METHOD %s
// RUN: llvm-bcanalyzer %t/invalidMethodUse.swiftmodule | %FileCheck -check-prefix=CHECK-BC %s
#if INVALID_METHOD_USE
import errors
func test(s: ValidStructInvalidMember) {
s.funcBadArg()
}
// CHECK-INVALID-METHOD-NOT: allow-errors.swift:{{.*}} error:
// CHECK-INVALID-METHOD: error: allowing deserialization of error type '<null>' in module 'errors'
// CHECK-INVALID-METHOD: error: allowing deserialization of invalid declaration 'arg' (parameter) in module 'errors'
// CHECK-INVALID-METHOD: error: allowing deserialization of invalid declaration 'funcBadArg' (instance method) in module 'errors'
// CHECK-INVALID-METHOD-NOT: allow-errors.swift:{{.*}} error:
#endif
public func invalid() -> undefined {} // expected-error {{cannot find type 'undefined'}}
52 changes: 52 additions & 0 deletions test/Serialization/AllowErrors/invalid-inheritance.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/mods)

// RUN: touch %t/empty.swift
// RUN: %{python} %utils/split_file.py -o %t %s

// Errors often only occur during merging, hence creating an empty module here
// RUN: %target-swift-frontend -verify -module-name errors -emit-module -o %t/mods/errorsmain.partial.swiftmodule -experimental-allow-module-with-compiler-errors %t/errors.swift
// RUN: %target-swift-frontend -module-name errors -emit-module -o %t/mods/errorsempty.partial.swiftmodule %t/empty.swift
// RUN: %target-swift-frontend -module-name errors -emit-module -o %t/mods/errors.swiftmodule -experimental-allow-module-with-compiler-errors %t/mods/errorsmain.partial.swiftmodule %t/mods/errorsempty.partial.swiftmodule

// RUN: %target-swift-frontend -emit-module -o %t/mods/uses.swiftmodule -experimental-allow-module-with-compiler-errors -I %t/mods %t/uses.swift 2>&1 | %FileCheck -check-prefix=CHECK-USES %s

// BEGIN errors.swift
public protocol SomeProto: undefined {} // expected-error {{cannot find type 'undefined'}}
public class SomeClass: undefined {} // expected-error {{cannot find type 'undefined'}}
public struct SomeStruct: undefined {} // expected-error {{cannot find type 'undefined'}}
public enum SomeEnum: undefined { // expected-error {{cannot find type 'undefined'}}
case a
}

public class GenericClass<T> {}
public class InvalidGenericSuperclass: GenericClass<undefined> {} // expected-error {{cannot find type 'undefined'}}

extension SomeClass: undefined {} // expected-error {{cannot find type 'undefined'}}
extension SomeStruct: undefined {} // expected-error {{cannot find type 'undefined'}}
extension SomeEnum: undefined {} // expected-error {{cannot find type 'undefined'}}

extension undefined {} // expected-error {{cannot find type 'undefined'}}
extension undefined: undefined {} // expected-error {{cannot find type 'undefined'}}
extension undefined: SomeProto {} // expected-error {{cannot find type 'undefined'}}

public extension undefined { // expected-error {{cannot find type 'undefined' in scope}}
protocol SomeProtoInner: undefined {} // expected-error {{cannot find type 'undefined' in scope}}
// TODO: Why don't these have errors?
class SomeClassInner: undefined {}
struct SomeStructInner: undefined {}
enum SomeEnumInner: undefined { // expected-error {{cannot find type 'undefined' in scope}}
case a
}
class InvalidGenericSuperclassInner: GenericClass<undefined> {} // expected-error {{cannot find type 'undefined' in scope}}
}


// BEGIN uses.swift
import errors
func test(p: SomeProto, c: SomeClass, s: SomeStruct, e: SomeEnum, g: InvalidGenericSuperclass) {}
// CHECK-USES-NOT: cannot find type 'SomeProto' in scope
// CHECK-USES-NOT: cannot find type 'SomeClass' in scope
// CHECK-USES-NOT: cannot find type 'SomeStruct' in scope
// CHECK-USES-NOT: cannot find type 'SomeEnum' in scope
// CHECK-USES-NOT: cannot find type 'InvalidGenericSuperclass' in scope
72 changes: 72 additions & 0 deletions test/Serialization/AllowErrors/invalid-members.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/mods)

// RUN: touch %t/empty.swift
// RUN: %{python} %utils/split_file.py -o %t %s

// Errors often only occur during merging, hence creating an empty module here
// RUN: %target-swift-frontend -verify -module-name errors -emit-module -o %t/mods/errorsmain.partial.swiftmodule -experimental-allow-module-with-compiler-errors %t/errors.swift
// RUN: %target-swift-frontend -module-name errors -emit-module -o %t/mods/errorsempty.partial.swiftmodule %t/empty.swift
// RUN: %target-swift-frontend -module-name errors -emit-module -o %t/mods/errors.swiftmodule -experimental-allow-module-with-compiler-errors %t/mods/errorsmain.partial.swiftmodule %t/mods/errorsempty.partial.swiftmodule

// RUN: %target-swift-frontend -emit-module -o %t/mods/uses.swiftmodule -experimental-allow-module-with-compiler-errors -I %t/mods %t/uses.swift 2>&1 | %FileCheck -check-prefix=CHECK-USES %s

// BEGIN errors.swift
public struct ValidStructInvalidMember {
public var member: String
public let memberMissingType: undefined // expected-error {{cannot find type 'undefined'}}

public var memberMissingTypeValidSets: undefined { // expected-error {{cannot find type 'undefined'}}
willSet {
print("Setting value \(newValue)")
}
didSet {
print("Set value \(oldValue)")
}
}
public var memberInvalidSets: Int {
willSet {
undefined // expected-error {{cannot find 'undefined'}}
}
didSet {
undefined // expected-error {{cannot find 'undefined'}}
}
}

public lazy var lazyMemberMissingTypeValidBody: undefined = { // expected-error {{cannot find type 'undefined'}}
return ""
}()
public lazy var lazyMemberInvalidBody: String = {
return undefined // expected-error {{cannot find 'undefined'}}
}()

public var memberMissingTypeValidGetSets: String {
get { member }
set { member = "" }
}
public var memberInvalidGetSet: String {
get { undefined } // expected-error {{cannot find 'undefined'}}
set { undefined = "" } // expected-error {{cannot find 'undefined'}}
}

public func someFunc() {}
public func funcBadArg(_ arg: undefined? = nil) {} // expected-error {{cannot find type 'undefined'}}
}


// BEGIN uses.swift
import errors

func test(s: ValidStructInvalidMember) {
s.someFunc()
s.BOOOP()
print(s.member)

s.funcBadArg()
print(s.memberMissingType)
}

// CHECK-USES-NOT: has no member 'someFunc'
// CHECK-USES-NOT: has no member 'member'
// CHECK-USES-NOT: has no member 'funcBadArg'
// CHECK-USES-NOT: has no member 'memberMissingType'
57 changes: 57 additions & 0 deletions test/Serialization/AllowErrors/invalid-top.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/mods)

// RUN: touch %t/empty.swift
// RUN: %{python} %utils/split_file.py -o %t %s

// Errors often only occur during merging, hence creating an empty module here
// RUN: %target-swift-frontend -verify -module-name errors -emit-module -o %t/mods/errorsmain.partial.swiftmodule -experimental-allow-module-with-compiler-errors %t/errors.swift
// RUN: %target-swift-frontend -module-name errors -emit-module -o %t/mods/errorsempty.partial.swiftmodule %t/empty.swift
// RUN: %target-swift-frontend -module-name errors -emit-module -o %t/mods/errors.swiftmodule -experimental-allow-module-with-compiler-errors %t/mods/errorsmain.partial.swiftmodule %t/mods/errorsempty.partial.swiftmodule

// RUN: %target-swift-frontend -emit-module -o %t/mods/validUses.swiftmodule -experimental-allow-module-with-compiler-errors -I%t/mods %t/valid-uses.swift 2>&1 | %FileCheck -check-prefix=CHECK-VALID %s

// RUN: %target-swift-frontend -emit-module -o %t/mods/invalidUses.swiftmodule -experimental-allow-module-with-compiler-errors -I%t/mods %t/invalid-uses.swift 2>&1 | %FileCheck -check-prefix=CHECK-INVALID %s

// BEGIN errors.swift
public struct ValidType {}

public func validFunc() -> ValidType { return ValidType() }

public func invalidFuncBody() -> ValidType {
ret // expected-error {{cannot find 'ret'}}
}

public func invalidFuncRet() -> undefined {} // expected-error {{cannot find type 'undefined'}}


// BEGIN valid-uses.swift
import errors

func test(s: ValidType) {
print(validFunc())
print(invalidFuncBody())
}

// Check SIL diagnostics are still output (no reason not to output SIL since
// there were no errors)
func other() -> Int {}
// CHECK-VALID: valid-uses.swift:10:22: error: missing return
func other2() -> Bool {}
// CHECK-VALID: valid-uses.swift:12:24: error: missing return


// BEGIN invalid-uses.swift
import errors

func test() {
invalidFuncRet()
}

// All invalid uses should have no errors in the file itself - all referenced
// invalid declarations should have an error elsewhere (but we don't care what
// that location is)
// CHECK-INVALID-NOT: invalid-uses.swift:{{.*}} error:
// CHECK-INVALID: error: allowing deserialization of error type '<null>' in module 'errors'
// CHECK-INVALID: error: allowing deserialization of invalid declaration 'invalidFuncRet()' (global function) in module 'errors'
// CHECK-INVALID-NOT: invalid-uses.swift:{{.*}} error: