Skip to content
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
18 changes: 17 additions & 1 deletion include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -645,14 +645,30 @@ class FunctionArgApplyInfo {
FunctionType *FnType;
const ValueDecl *Callee;

public:
FunctionArgApplyInfo(ArgumentList *argList, Expr *argExpr, unsigned argIdx,
Type argType, unsigned paramIdx, Type fnInterfaceType,
FunctionType *fnType, const ValueDecl *callee)
: ArgList(argList), ArgExpr(argExpr), ArgIdx(argIdx), ArgType(argType),
ParamIdx(paramIdx), FnInterfaceType(fnInterfaceType), FnType(fnType),
Callee(callee) {}

public:
static Optional<FunctionArgApplyInfo>
get(ArgumentList *argList, Expr *argExpr, unsigned argIdx, Type argType,
unsigned paramIdx, Type fnInterfaceType, FunctionType *fnType,
const ValueDecl *callee) {
assert(fnType);

if (argIdx >= argList->size())
return None;

if (paramIdx >= fnType->getNumParams())
return None;

return FunctionArgApplyInfo(argList, argExpr, argIdx, argType, paramIdx,
fnInterfaceType, fnType, callee);
}

/// \returns The list of the arguments used for this application.
ArgumentList *getArgList() const { return ArgList; }

Expand Down
6 changes: 3 additions & 3 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5619,9 +5619,9 @@ Solution::getFunctionArgApplyInfo(ConstraintLocator *locator) const {
auto argIdx = applyArgElt->getArgIdx();
auto paramIdx = applyArgElt->getParamIdx();

return FunctionArgApplyInfo(argList, argExpr, argIdx,
simplifyType(getType(argExpr)), paramIdx,
fnInterfaceType, fnType, callee);
return FunctionArgApplyInfo::get(argList, argExpr, argIdx,
simplifyType(getType(argExpr)), paramIdx,
fnInterfaceType, fnType, callee);
}

bool constraints::isKnownKeyPathType(Type type) {
Expand Down
14 changes: 13 additions & 1 deletion lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,8 @@ UnderlyingTypeRequest::evaluate(Evaluator &evaluator,
TypeResolutionOptions options((typeAlias->getGenericParams()
? TypeResolverContext::GenericTypeAliasDecl
: TypeResolverContext::TypeAliasDecl));
if (typeAlias->preconcurrency())
options |= TypeResolutionFlags::Preconcurrency;

// This can happen when code completion is attempted inside
// of typealias underlying type e.g. `typealias F = () -> Int#^TOK^#`
Expand Down Expand Up @@ -2094,8 +2096,11 @@ ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
: ErrorType::get(ctx));
}

const auto options =
auto options =
TypeResolutionOptions(TypeResolverContext::FunctionResult);
if (decl->preconcurrency())
options |= TypeResolutionFlags::Preconcurrency;

auto *const dc = decl->getInnermostDeclContext();
return TypeResolution::forInterface(dc, options,
/*unboundTyOpener*/ nullptr,
Expand Down Expand Up @@ -2196,6 +2201,13 @@ static Type validateParameterType(ParamDecl *decl) {
options = TypeResolutionOptions(TypeResolverContext::EnumElementDecl);
}

// Set the "preconcurrency" flag if this is a parameter of a preconcurrency
// declaration.
if (auto decl = dc->getAsDecl()) {
if (decl->preconcurrency())
options |= TypeResolutionFlags::Preconcurrency;
}

// If the element is a variadic parameter, resolve the parameter type as if
// it were in non-parameter position, since we want functions to be
// @escaping in this case.
Expand Down
58 changes: 52 additions & 6 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,37 @@ static Type getIdentityOpaqueTypeArchetypeType(
return OpaqueTypeArchetypeType::get(opaqueDecl, interfaceType, subs);
}

/// Adjust the underlying type of a typealias within the given context to
/// account for @preconcurrency.
static Type adjustTypeAliasTypeInContext(
Type type, TypeAliasDecl *aliasDecl, DeclContext *fromDC,
TypeResolutionOptions options) {
// If we are in a @preconcurrency declaration, don't adjust the types of
// type aliases.
if (options.contains(TypeResolutionFlags::Preconcurrency))
return type;

// If the type alias itself isn't marked with @preconcurrency, don't
// adjust the type.
if (!aliasDecl->preconcurrency())
return type;

// Only adjust the type within a strict concurrency context, so we don't
// change the types as seen by code that hasn't adopted concurrency.
if (contextRequiresStrictConcurrencyChecking(
fromDC,
[](const AbstractClosureExpr *closure) {
return closure->getType();
},
[](const ClosureExpr *closure) {
return closure->isIsolatedByPreconcurrency();
}))
return type;

return type->stripConcurrency(
/*recurse=*/true, /*dropGlobalActor=*/true);
}

Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
DeclContext *foundDC,
bool isSpecialized) const {
Expand All @@ -307,6 +338,13 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
return genericParam->getDeclaredInterfaceType();
}

/// Call this function before returning the underlying type of a typealias,
/// to adjust its type for concurrency.
auto adjustAliasType = [&](Type type) -> Type {
return adjustTypeAliasTypeInContext(
type, cast<TypeAliasDecl>(typeDecl), fromDC, options);
};

if (!isSpecialized) {
// If we are referring to a type within its own context, and we have either
// a generic type with no generic arguments or a non-generic type, use the
Expand Down Expand Up @@ -342,9 +380,9 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
if (ugAliasDecl == aliasDecl) {
if (getStage() == TypeResolutionStage::Structural &&
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
return aliasDecl->getStructuralType();
return adjustAliasType(aliasDecl->getStructuralType());
}
return aliasDecl->getDeclaredInterfaceType();
return adjustAliasType(aliasDecl->getDeclaredInterfaceType());
}

extendedType = unboundGeneric->getParent();
Expand All @@ -356,9 +394,9 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
if (aliasType->getDecl() == aliasDecl) {
if (getStage() == TypeResolutionStage::Structural &&
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
return aliasDecl->getStructuralType();
return adjustAliasType(aliasDecl->getStructuralType());
}
return aliasDecl->getDeclaredInterfaceType();
return adjustAliasType(aliasDecl->getDeclaredInterfaceType());
}
extendedType = aliasType->getParent();
continue;
Expand All @@ -381,9 +419,9 @@ Type TypeResolution::resolveTypeInContext(TypeDecl *typeDecl,
// Otherwise, return the appropriate type.
if (getStage() == TypeResolutionStage::Structural &&
aliasDecl->getUnderlyingTypeRepr() != nullptr) {
return aliasDecl->getStructuralType();
return adjustAliasType(aliasDecl->getStructuralType());
}
return aliasDecl->getDeclaredInterfaceType();
return adjustAliasType(aliasDecl->getDeclaredInterfaceType());
}

// When a nominal type used outside its context, return the unbound
Expand Down Expand Up @@ -1571,6 +1609,13 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution,
AssociatedTypeDecl *inferredAssocType) {
bool hasUnboundOpener = !!resolution.getUnboundTypeOpener();

// Type aliases might require adjustment due to @preconcurrency.
if (auto aliasDecl = dyn_cast<TypeAliasDecl>(member)) {
memberType = adjustTypeAliasTypeInContext(
memberType, aliasDecl, resolution.getDeclContext(),
resolution.getOptions());
}

if (options.contains(TypeResolutionFlags::SilenceErrors)) {
if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member,
hasUnboundOpener)
Expand Down Expand Up @@ -4401,6 +4446,7 @@ class ExistentialTypeVisitor
}
} else if (auto *alias = dyn_cast_or_null<TypeAliasDecl>(comp->getBoundDecl())) {
auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType());

// If this is a type alias to a constraint type, the type
// alias name must be prefixed with 'any' to be used as an
// existential type.
Expand Down
3 changes: 3 additions & 0 deletions lib/Sema/TypeCheckType.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ enum class TypeResolutionFlags : uint16_t {
/// Needed to enforce that \c any P<some Q> does not resolve to a
/// parameterized existential with an opaque type constraint.
DisallowOpaqueTypes = 1 << 9,

/// We are in a `@preconcurrency` declaration.
Preconcurrency = 1 << 10,
};

/// Type resolution contexts that require special handling.
Expand Down
48 changes: 48 additions & 0 deletions test/Concurrency/preconcurrency_typealias.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// RUN: %target-swift-frontend -typecheck -verify %s
// REQUIRES: concurrency

@preconcurrency @MainActor func f() { }
// expected-note@-1 2{{calls to global function 'f()' from outside of its actor context are implicitly asynchronous}}

@preconcurrency typealias FN = @Sendable () -> Void

struct Outer {
@preconcurrency typealias FN = @Sendable () -> Void
}

@preconcurrency func preconcurrencyFunc(callback: FN) {}

func test() {
var _: Outer.FN = {
f()
}

var _: FN = {
f()
print("Hello")
}

var mutableVariable = 0
preconcurrencyFunc {
mutableVariable += 1 // no sendable warning
}
mutableVariable += 1
}

@available(SwiftStdlib 5.1, *)
func testAsync() async {
var _: Outer.FN = {
f() // expected-error{{call to main actor-isolated global function 'f()' in a synchronous nonisolated context}}
}

var _: FN = {
f() // expected-error{{call to main actor-isolated global function 'f()' in a synchronous nonisolated context}}
print("Hello")
}

var mutableVariable = 0
preconcurrencyFunc {
mutableVariable += 1 // expected-warning{{mutation of captured var 'mutableVariable' in concurrently-executing code; this is an error in Swift 6}}
}
mutableVariable += 1
}
8 changes: 8 additions & 0 deletions test/Constraints/argument_matching.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1789,3 +1789,11 @@ func rdar93922410(_ completion: (Int?) -> Void) { // expected-note {{'completion
return completion() // expected-error {{missing argument for parameter #1 in call}}
}
}

// https://github.com/apple/swift/issues/60436
func test_extraneous_argument_with_inout() {
func test(_: Int) {}

var x: Int = 0
test(42, &x) // expected-error {{extra argument in call}}
}