mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
For now, the accessors have been underscored as `_read` and `_modify`. I'll prepare an evolution proposal for this feature which should allow us to remove the underscores or, y'know, rename them to `purple` and `lettuce`. `_read` accessors do not make any effort yet to avoid copying the value being yielded. I'll work on it in follow-up patches. Opaque accesses to properties and subscripts defined with `_modify` accessors will use an inefficient `materializeForSet` pattern that materializes the value to a temporary instead of accessing it in-place. That will be fixed by migrating to `modify` over `materializeForSet`, which is next up after the `read` optimizations. SIL ownership verification doesn't pass yet for the test cases here because of a general fault in SILGen where borrows can outlive their borrowed value due to being cleaned up on the general cleanup stack when the borrowed value is cleaned up on the formal-access stack. Michael, Andy, and I discussed various ways to fix this, but it seems clear to me that it's not in any way specific to coroutine accesses. rdar://35399664
261 lines
7.8 KiB
C++
261 lines
7.8 KiB
C++
//===--- NameLookupImpl.h - Helpers used to implement lookup ----*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_AST_NAME_LOOKUP_IMPL_H
|
|
#define SWIFT_AST_NAME_LOOKUP_IMPL_H
|
|
|
|
#include "swift/AST/NameLookup.h"
|
|
#include "swift/AST/ASTVisitor.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
|
|
namespace swift {
|
|
namespace namelookup {
|
|
|
|
/// Performs a qualified lookup into the given module and, if necessary, its
|
|
/// reexports, observing proper shadowing rules.
|
|
void
|
|
lookupVisibleDeclsInModule(ModuleDecl *M, ModuleDecl::AccessPathTy accessPath,
|
|
SmallVectorImpl<ValueDecl *> &decls,
|
|
NLKind lookupKind,
|
|
ResolutionKind resolutionKind,
|
|
LazyResolver *typeResolver,
|
|
const DeclContext *moduleScopeContext,
|
|
ArrayRef<ModuleDecl::ImportedModule> extraImports = {});
|
|
|
|
/// Searches through statements and patterns for local variable declarations.
|
|
class FindLocalVal : public StmtVisitor<FindLocalVal> {
|
|
friend class ASTVisitor<FindLocalVal>;
|
|
|
|
const SourceManager &SM;
|
|
SourceLoc Loc;
|
|
VisibleDeclConsumer &Consumer;
|
|
|
|
public:
|
|
FindLocalVal(const SourceManager &SM, SourceLoc Loc,
|
|
VisibleDeclConsumer &Consumer)
|
|
: SM(SM), Loc(Loc), Consumer(Consumer) {}
|
|
|
|
void checkValueDecl(ValueDecl *D, DeclVisibilityKind Reason) {
|
|
Consumer.foundDecl(D, Reason);
|
|
}
|
|
|
|
void checkPattern(const Pattern *Pat, DeclVisibilityKind Reason) {
|
|
switch (Pat->getKind()) {
|
|
case PatternKind::Tuple:
|
|
for (auto &field : cast<TuplePattern>(Pat)->getElements())
|
|
checkPattern(field.getPattern(), Reason);
|
|
return;
|
|
case PatternKind::Paren:
|
|
case PatternKind::Typed:
|
|
case PatternKind::Var:
|
|
return checkPattern(Pat->getSemanticsProvidingPattern(), Reason);
|
|
case PatternKind::Named:
|
|
return checkValueDecl(cast<NamedPattern>(Pat)->getDecl(), Reason);
|
|
case PatternKind::EnumElement: {
|
|
auto *OP = cast<EnumElementPattern>(Pat);
|
|
if (OP->hasSubPattern())
|
|
checkPattern(OP->getSubPattern(), Reason);
|
|
return;
|
|
}
|
|
case PatternKind::OptionalSome:
|
|
checkPattern(cast<OptionalSomePattern>(Pat)->getSubPattern(), Reason);
|
|
return;
|
|
|
|
case PatternKind::Is: {
|
|
auto *isPat = cast<IsPattern>(Pat);
|
|
if (isPat->hasSubPattern())
|
|
checkPattern(isPat->getSubPattern(), Reason);
|
|
return;
|
|
}
|
|
|
|
// Handle non-vars.
|
|
case PatternKind::Bool:
|
|
case PatternKind::Expr:
|
|
case PatternKind::Any:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void checkParameterList(const ParameterList *params) {
|
|
for (auto param : *params) {
|
|
checkValueDecl(param, DeclVisibilityKind::FunctionParameter);
|
|
}
|
|
}
|
|
|
|
void checkGenericParams(GenericParamList *Params) {
|
|
if (!Params)
|
|
return;
|
|
|
|
for (auto P : *Params)
|
|
checkValueDecl(P, DeclVisibilityKind::GenericParameter);
|
|
}
|
|
|
|
void checkSourceFile(const SourceFile &SF) {
|
|
for (Decl *D : SF.Decls)
|
|
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D))
|
|
visitBraceStmt(TLCD->getBody(), /*isTopLevel=*/true);
|
|
}
|
|
|
|
private:
|
|
bool isReferencePointInRange(SourceRange R) {
|
|
return SM.rangeContainsTokenLoc(R, Loc);
|
|
}
|
|
|
|
void visitBreakStmt(BreakStmt *) {}
|
|
void visitContinueStmt(ContinueStmt *) {}
|
|
void visitFallthroughStmt(FallthroughStmt *) {}
|
|
void visitFailStmt(FailStmt *) {}
|
|
void visitReturnStmt(ReturnStmt *) {}
|
|
void visitYieldStmt(YieldStmt *) {}
|
|
void visitThrowStmt(ThrowStmt *) {}
|
|
void visitDeferStmt(DeferStmt *DS) {
|
|
// Nothing in the defer is visible.
|
|
}
|
|
|
|
void checkStmtCondition(const StmtCondition &Cond) {
|
|
SourceLoc start = SourceLoc();
|
|
for (auto entry : Cond) {
|
|
if (start.isInvalid())
|
|
start = entry.getStartLoc();
|
|
if (auto *P = entry.getPatternOrNull()) {
|
|
SourceRange previousConditionsToHere = SourceRange(start, entry.getEndLoc());
|
|
if (!isReferencePointInRange(previousConditionsToHere))
|
|
checkPattern(P, DeclVisibilityKind::LocalVariable);
|
|
}
|
|
}
|
|
}
|
|
|
|
void visitIfStmt(IfStmt *S) {
|
|
if (!isReferencePointInRange(S->getSourceRange()))
|
|
return;
|
|
|
|
if (!S->getElseStmt() ||
|
|
!isReferencePointInRange(S->getElseStmt()->getSourceRange())) {
|
|
checkStmtCondition(S->getCond());
|
|
}
|
|
|
|
visit(S->getThenStmt());
|
|
if (S->getElseStmt())
|
|
visit(S->getElseStmt());
|
|
}
|
|
void visitGuardStmt(GuardStmt *S) {
|
|
if (SM.isBeforeInBuffer(Loc, S->getStartLoc()))
|
|
return;
|
|
|
|
// Names in the guard aren't visible until after the body.
|
|
if (!isReferencePointInRange(S->getBody()->getSourceRange()))
|
|
checkStmtCondition(S->getCond());
|
|
|
|
visit(S->getBody());
|
|
}
|
|
|
|
void visitWhileStmt(WhileStmt *S) {
|
|
if (!isReferencePointInRange(S->getSourceRange()))
|
|
return;
|
|
|
|
checkStmtCondition(S->getCond());
|
|
visit(S->getBody());
|
|
}
|
|
void visitRepeatWhileStmt(RepeatWhileStmt *S) {
|
|
visit(S->getBody());
|
|
}
|
|
void visitDoStmt(DoStmt *S) {
|
|
visit(S->getBody());
|
|
}
|
|
|
|
void visitForEachStmt(ForEachStmt *S) {
|
|
if (!isReferencePointInRange(S->getSourceRange()))
|
|
return;
|
|
visit(S->getBody());
|
|
if (!isReferencePointInRange(S->getSequence()->getSourceRange()))
|
|
checkPattern(S->getPattern(), DeclVisibilityKind::LocalVariable);
|
|
}
|
|
|
|
void visitBraceStmt(BraceStmt *S, bool isTopLevelCode = false) {
|
|
if (isTopLevelCode) {
|
|
if (SM.isBeforeInBuffer(Loc, S->getStartLoc()))
|
|
return;
|
|
} else {
|
|
if (!isReferencePointInRange(S->getSourceRange()))
|
|
return;
|
|
}
|
|
|
|
for (auto elem : S->getElements()) {
|
|
if (auto *S = elem.dyn_cast<Stmt*>())
|
|
visit(S);
|
|
}
|
|
for (auto elem : S->getElements()) {
|
|
if (auto *D = elem.dyn_cast<Decl*>()) {
|
|
if (auto *VD = dyn_cast<ValueDecl>(D))
|
|
checkValueDecl(VD, DeclVisibilityKind::LocalVariable);
|
|
}
|
|
}
|
|
}
|
|
|
|
void visitSwitchStmt(SwitchStmt *S) {
|
|
if (!isReferencePointInRange(S->getSourceRange()))
|
|
return;
|
|
for (CaseStmt *C : S->getCases()) {
|
|
visit(C);
|
|
}
|
|
}
|
|
|
|
void visitCaseStmt(CaseStmt *S) {
|
|
if (!isReferencePointInRange(S->getSourceRange()))
|
|
return;
|
|
// Pattern names aren't visible in the patterns themselves,
|
|
// just in the body or in where guards.
|
|
auto body = S->getBody();
|
|
bool inPatterns = isReferencePointInRange(S->getLabelItemsRange());
|
|
auto items = S->getCaseLabelItems();
|
|
if (inPatterns) {
|
|
for (const auto &CLI : items) {
|
|
auto guard = CLI.getGuardExpr();
|
|
if (guard && isReferencePointInRange(guard->getSourceRange())) {
|
|
inPatterns = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!inPatterns && !items.empty())
|
|
checkPattern(items[0].getPattern(), DeclVisibilityKind::LocalVariable);
|
|
visit(body);
|
|
}
|
|
|
|
void visitDoCatchStmt(DoCatchStmt *S) {
|
|
if (!isReferencePointInRange(S->getSourceRange()))
|
|
return;
|
|
visit(S->getBody());
|
|
visitCatchClauses(S->getCatches());
|
|
}
|
|
void visitCatchClauses(ArrayRef<CatchStmt*> clauses) {
|
|
// TODO: some sort of binary search?
|
|
for (auto clause : clauses) {
|
|
visitCatchStmt(clause);
|
|
}
|
|
}
|
|
void visitCatchStmt(CatchStmt *S) {
|
|
if (!isReferencePointInRange(S->getSourceRange()))
|
|
return;
|
|
// Names in the pattern aren't visible until after the pattern.
|
|
if (!isReferencePointInRange(S->getErrorPattern()->getSourceRange()))
|
|
checkPattern(S->getErrorPattern(), DeclVisibilityKind::LocalVariable);
|
|
visit(S->getBody());
|
|
}
|
|
|
|
};
|
|
|
|
} // end namespace namelookup
|
|
} // end namespace swift
|
|
|
|
#endif
|