Skip to content

Sema/SIL: NSError has no special powers without ObjC interop. #7761

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 1 commit into from
Feb 25, 2017
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
29 changes: 18 additions & 11 deletions lib/SIL/DynamicCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1139,23 +1139,30 @@ bool swift::canUseScalarCheckedCastInstructions(SILModule &M,
// non-NSError superclass constraint. Casts to archetypes thus must always be
// indirect.
if (auto archetype = targetType->getAs<ArchetypeType>()) {
auto super = archetype->getSuperclass();
if (super.isNull())
return false;

// Only ever permit this if the source type is a reference type.
if (!objectType.isAnyClassReferenceType())
return false;

if (M.getASTContext().LangOpts.EnableObjCInterop) {
auto super = archetype->getSuperclass();
if (super.isNull())
return false;

// A base class constraint that isn't NSError rules out the archetype being
// bound to NSError.
if (auto nserror = M.Types.getNSErrorType())
return !super->isEqual(nserror);
// If NSError wasn't loaded, any base class constraint must not be NSError.
return true;
// A base class constraint that isn't NSError rules out the archetype being
// bound to NSError.
if (auto nserror = M.Types.getNSErrorType())
return !super->isEqual(nserror);
// If NSError wasn't loaded, any base class constraint must not be NSError.
return true;
} else {
// If ObjC bridging isn't enabled, we can do a scalar cast from any
// reference type to any class-constrained archetype.
return archetype->requiresClass();
}
}

if (targetType == M.Types.getNSErrorType()) {
if (M.getASTContext().LangOpts.EnableObjCInterop
&& targetType == M.Types.getNSErrorType()) {
// If we statically know the source is an NSError subclass, then the cast
// can go through the scalar path (and it's trivially true so can be
// killed).
Expand Down
4 changes: 4 additions & 0 deletions lib/SIL/SILType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ SILType SILType::unwrapAnyOptionalType() const {
/// Error existentials.
static bool isBridgedErrorClass(SILModule &M,
Type t) {
// There's no bridging if ObjC interop is disabled.
if (!M.getASTContext().LangOpts.EnableObjCInterop)
return false;

if (!t)
return false;

Expand Down
4 changes: 4 additions & 0 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3351,6 +3351,10 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
Type type2,
TypeMatchOptions flags,
ConstraintLocatorBuilder locator) {
// There's no bridging without ObjC interop.
if (!TC.Context.LangOpts.EnableObjCInterop)
return SolutionKind::Error;

TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);

/// Form an unresolved result.
Expand Down
22 changes: 12 additions & 10 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3365,16 +3365,18 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
// We can conditionally cast from NSError to an Error-conforming
// type. This is handled in the runtime, so it doesn't need a special cast
// kind.
if (auto errorTypeProto = Context.getProtocol(KnownProtocolKind::Error)) {
if (conformsToProtocol(toType, errorTypeProto, dc,
(ConformanceCheckFlags::InExpression|
ConformanceCheckFlags::Used)))
if (auto NSErrorTy = getNSErrorType(dc))
if (isSubtypeOf(fromType, NSErrorTy, dc)
// Don't mask "always true" warnings if NSError is cast to
// Error itself.
&& !isSubtypeOf(fromType, toType, dc))
return CheckedCastKind::ValueCast;
if (Context.LangOpts.EnableObjCInterop) {
if (auto errorTypeProto = Context.getProtocol(KnownProtocolKind::Error)) {
if (conformsToProtocol(toType, errorTypeProto, dc,
(ConformanceCheckFlags::InExpression|
ConformanceCheckFlags::Used)))
if (auto NSErrorTy = getNSErrorType(dc))
if (isSubtypeOf(fromType, NSErrorTy, dc)
// Don't mask "always true" warnings if NSError is cast to
// Error itself.
&& !isSubtypeOf(fromType, toType, dc))
return CheckedCastKind::ValueCast;
}
}

// The runtime doesn't support casts to CF types and always lets them succeed.
Expand Down
8 changes: 0 additions & 8 deletions test/SIL/Parser/undef.sil
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,6 @@ bb0:
bridge_object_to_word undef : $Builtin.BridgeObject to $Builtin.Word
// CHECK: thin_to_thick_function undef : $@convention(thin) () -> () to $() -> ()
thin_to_thick_function undef : $@convention(thin) () -> () to $() -> ()
// CHECK: thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
// CHECK: objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
// CHECK: objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
// CHECK: objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
// CHECK: is_nonnull undef : $C
is_nonnull undef : $C

Expand Down
23 changes: 23 additions & 0 deletions test/SIL/Parser/undef_objc.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil %s | %target-sil-opt -assume-parsing-unqualified-ownership-sil | %FileCheck %s
// REQUIRES: objc_interop

sil_stage raw

import Builtin
import Swift

protocol P { }
class C { }

sil @general_test : $() -> () {
bb0:
// CHECK: thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
thick_to_objc_metatype undef : $@thick C.Type to $@objc_metatype C.Type
// CHECK: objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
objc_to_thick_metatype undef : $@objc_metatype C.Type to $@thick C.Type
// CHECK: objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
objc_metatype_to_object undef : $@objc_metatype C.Type to $AnyObject
// CHECK: objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
objc_existential_metatype_to_object undef : $@objc_metatype P.Type to $AnyObject
unreachable
}
26 changes: 17 additions & 9 deletions test/SILGen/generic_casts.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck %s
// RUN: %target-swift-frontend -Xllvm -sil-full-demangle -emit-silgen %s | %FileCheck --check-prefix=CHECK --check-prefix=CHECK-%target-runtime %s

protocol ClassBound : class {}
protocol NotClassBound {}
Expand Down Expand Up @@ -57,16 +57,21 @@ func opaque_archetype_is_class_archetype
func class_archetype_to_class_archetype
<T:ClassBound, U:ClassBound>(_ t:T) -> U {
return t as! U
// CHECK: unconditional_checked_cast_addr {{.*}} T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
// CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK: return [[DOWNCAST]] : $U
// Error bridging can change the identity of class-constrained archetypes.
// CHECK-objc: unconditional_checked_cast_addr {{.*}} T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
// CHECK-objc: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK-objc: return [[DOWNCAST]] : $U

// CHECK-native: [[DOWNCAST:%.*]] = unconditional_checked_cast {{.*}} : $T to $U
}

// CHECK-LABEL: sil hidden @_TF13generic_casts34class_archetype_is_class_archetype{{.*}}
func class_archetype_is_class_archetype
<T:ClassBound, U:ClassBound>(_ t:T, u:U.Type) -> Bool {
return t is U
// CHECK: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
// Error bridging can change the identity of class-constrained archetypes.
// CHECK-objc: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
// CHECK-native: checked_cast_br {{.*}} : $T to $U
}

// CHECK-LABEL: sil hidden @_TF13generic_casts38opaque_archetype_to_addr_only_concrete{{.*}}
Expand Down Expand Up @@ -156,16 +161,19 @@ func opaque_existential_is_class_archetype
func class_existential_to_class_archetype
<T:ClassBound>(_ p:ClassBound) -> T {
return p as! T
// CHECK: unconditional_checked_cast_addr {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
// CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK: return [[DOWNCAST]] : $T
// CHECK-objc: unconditional_checked_cast_addr {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
// CHECK-objc: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
// CHECK-objc: return [[DOWNCAST]] : $T

// CHECK-native: [[DOWNCAST:%.*]] = unconditional_checked_cast {{.*}} : $ClassBound to $T
}

// CHECK-LABEL: sil hidden @_TF13generic_casts36class_existential_is_class_archetype{{.*}}
func class_existential_is_class_archetype
<T:ClassBound>(_ p:ClassBound, _: T) -> Bool {
return p is T
// CHECK: checked_cast_addr_br {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in {{%.*}} : $*T
// CHECK-objc: checked_cast_addr_br {{.*}} ClassBound in {{%.*}} : $*ClassBound to T in {{%.*}} : $*T
// CHECK-native: checked_cast_br {{.*}} : $ClassBound to $T
}

// CHECK-LABEL: sil hidden @_TF13generic_casts40opaque_existential_to_addr_only_concrete{{.*}}
Expand Down
116 changes: 0 additions & 116 deletions test/SILOptimizer/cse.sil
Original file line number Diff line number Diff line change
Expand Up @@ -720,104 +720,6 @@ bb2:
%33 = return %32 : $()
}

// CHECK-LABEL: sil @cse_value_metatype
// CHECK: value_metatype $@objc_metatype
// CHECK: objc_metatype_to_object
// CHECK-NOT: value_metatype $@objc_metatype
// CHECK: strong_release
// CHECK: return
sil @cse_value_metatype : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $T):
%2 = value_metatype $@objc_metatype T.Type, %0 : $T
%4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
%5 = value_metatype $@objc_metatype T.Type, %0 : $T
%7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
strong_release %0 : $T
%9 = tuple (%4: $AnyObject, %7: $AnyObject)
return %9 : $(AnyObject, AnyObject)
}


@objc(XX) protocol XX {
}

// CHECK-LABEL: sil @cse_existential_metatype
// CHECK: existential_metatype $@objc_metatype
// CHECK: objc_existential_metatype_to_object
// CHECK-NOT: existential_metatype $@objc_metatype
// CHECK: strong_release
// CHECK: return
sil @cse_existential_metatype : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $XX):
%2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
%5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
strong_release %0 : $XX
%7 = tuple (%4: $AnyObject, %6: $AnyObject)
return %7 : $(AnyObject, AnyObject)
}

// CHECK-LABEL: sil @nocse_existential_metatype_addr
// CHECK: store
// CHECK: existential_metatype $@thick Any.Type
// CHECK: store
// CHECK: existential_metatype $@thick Any.Type
// CHECK: return
sil @nocse_existential_metatype_addr : $@convention(thin) (@owned B, @owned B) -> (@thick Any.Type, @thick Any.Type) {
bb0(%0 : $B, %1 : $B):
%2 = alloc_stack $Any
%3 = init_existential_addr %2 : $*Any, $B
store %0 to %3 : $*B
%5 = existential_metatype $@thick Any.Type, %2 : $*Any
store %1 to %3 : $*B
%7 = existential_metatype $@thick Any.Type, %2 : $*Any
strong_release %1 : $B
strong_release %0 : $B
%99 = tuple (%5 : $@thick Any.Type, %7 : $@thick Any.Type)
dealloc_stack %2 : $*Any
return %99 : $(@thick Any.Type, @thick Any.Type)
}


// CHECK-LABEL: sil @cse_objc_metatype_to_object
// CHECK: value_metatype $@objc_metatype
// CHECK: objc_metatype_to_object
// CHECK-NOT: value_metatype $@objc_metatype
// CHECK-NOT: objc_metatype_to_object
// CHECK: strong_release
// CHECK: return
sil @cse_objc_metatype_to_object : $@convention(thin) <T where T : AnyObject> (@owned T) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $T):
%2 = value_metatype $@objc_metatype T.Type, %0 : $T
%4 = objc_metatype_to_object %2 : $@objc_metatype T.Type to $AnyObject
%5 = value_metatype $@objc_metatype T.Type, %0 : $T
%7 = objc_metatype_to_object %5 : $@objc_metatype T.Type to $AnyObject
strong_release %0 : $T
%9 = tuple (%4: $AnyObject, %7: $AnyObject)
return %9 : $(AnyObject, AnyObject)
}


// CHECK-LABEL: sil @cse_objc_existential_metatype_to_object
// CHECK: existential_metatype $@objc_metatype
// CHECK: objc_existential_metatype_to_object
// CHECK-NOT: existential_metatype $@objc_metatype
// CHECK-NOT: objc_existential_metatype_to_object
// CHECK: strong_release
// CHECK: return
sil @cse_objc_existential_metatype_to_object : $@convention(thin) (@owned XX) -> @owned (AnyObject, AnyObject) {
bb0(%0 : $XX):
%2 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%4 = objc_existential_metatype_to_object %2 : $@objc_metatype XX.Type to $AnyObject
%5 = existential_metatype $@objc_metatype XX.Type, %0 : $XX
%6 = objc_existential_metatype_to_object %5 : $@objc_metatype XX.Type to $AnyObject
strong_release %0 : $XX
%7 = tuple (%4: $AnyObject, %6: $AnyObject)
return %7 : $(AnyObject, AnyObject)
}


// CHECK-LABEL: sil @cse_raw_pointer_to_ref
// CHECK: raw_pointer_to_ref
// CHECK-NOT: raw_pointer_to_ref
Expand Down Expand Up @@ -937,24 +839,6 @@ bb0(%0 : $Enum1):
return %3: $(Builtin.Int1, Builtin.Int1)
}


@objc
class XXX {
}

// CHECK-LABEL: sil @cse_objc_to_thick_metatype
// CHECK: objc_to_thick_metatype
// CHECK-NOT: objc_to_thick_metatype
// CHECK: tuple
// CHECK: return
sil @cse_objc_to_thick_metatype : $@convention(thin) (@objc_metatype XXX.Type) -> (@thick XXX.Type, @thick XXX.Type) {
bb0(%0 : $@objc_metatype XXX.Type):
%1 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
%2 = objc_to_thick_metatype %0 : $@objc_metatype XXX.Type to $@thick XXX.Type
%3 = tuple (%1: $@thick XXX.Type, %2: $@thick XXX.Type)
return %3: $(@thick XXX.Type, @thick XXX.Type)
}

// CHECK-LABEL: sil @cse_bridge_object_to_ref
// CHECK: bridge_object_to_ref
// CHECK-NOT: bridge_object_to_ref
Expand Down
Loading