mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Implement static name resolution (#958)
This doesn't actually use the results of name resolution, but it does verify that they are present. Also ensures that name resolution and type checking are applied to deduced function parameters and the implicit call to `Main()`. Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
Jon Meow
parent
dc5e62fc7a
commit
17e0a1afb9
@@ -56,6 +56,7 @@ void PopulateNamesInStatement(Arena* arena,
|
||||
case StatementKind::Block: {
|
||||
// Defines a new scope for names.
|
||||
auto& block = cast<Block>(statement);
|
||||
block.static_scope().AddParent(&static_scope);
|
||||
for (const auto& statement : block.statements()) {
|
||||
PopulateNamesInStatement(arena, statement, block.static_scope());
|
||||
}
|
||||
@@ -91,6 +92,7 @@ void PopulateNamesInStatement(Arena* arena,
|
||||
// Contains blocks.
|
||||
auto& match = cast<Match>(statement);
|
||||
for (auto& clause : match.clauses()) {
|
||||
clause.static_scope().AddParent(&static_scope);
|
||||
PopulateNamesInPattern(clause.pattern(), clause.static_scope());
|
||||
PopulateNamesInStatement(arena, &clause.statement(),
|
||||
clause.static_scope());
|
||||
@@ -132,16 +134,18 @@ void PopulateNamesInDeclaration(Arena* arena, Declaration& declaration,
|
||||
switch (declaration.kind()) {
|
||||
case DeclarationKind::FunctionDeclaration: {
|
||||
auto& func = cast<FunctionDeclaration>(declaration);
|
||||
func.static_scope().AddParent(&static_scope);
|
||||
static_scope.Add(func.name(), &declaration);
|
||||
for (Nonnull<const GenericBinding*> param : func.deduced_parameters()) {
|
||||
func.static_scope().Add(param->name(), param);
|
||||
}
|
||||
PopulateNamesInPattern(func.param_pattern(), func.static_scope());
|
||||
PopulateNamesInStatement(arena, func.body(), static_scope);
|
||||
PopulateNamesInStatement(arena, func.body(), func.static_scope());
|
||||
break;
|
||||
}
|
||||
case DeclarationKind::ClassDeclaration: {
|
||||
auto& class_decl = cast<ClassDeclaration>(declaration);
|
||||
class_decl.static_scope().AddParent(&static_scope);
|
||||
static_scope.Add(class_decl.name(), &declaration);
|
||||
for (auto* member : class_decl.members()) {
|
||||
PopulateNamesInMember(arena, *member, class_decl.static_scope());
|
||||
@@ -150,6 +154,7 @@ void PopulateNamesInDeclaration(Arena* arena, Declaration& declaration,
|
||||
}
|
||||
case DeclarationKind::ChoiceDeclaration: {
|
||||
auto& choice = cast<ChoiceDeclaration>(declaration);
|
||||
choice.static_scope().AddParent(&static_scope);
|
||||
static_scope.Add(choice.name(), &declaration);
|
||||
for (Nonnull<const AlternativeSignature*> alt : choice.alternatives()) {
|
||||
choice.static_scope().Add(alt->name(), alt);
|
||||
@@ -168,19 +173,222 @@ void PopulateNamesInDeclaration(Arena* arena, Declaration& declaration,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ResolveNames for Expression, Member, Pattern, and Statement will be
|
||||
// needed for recursion.
|
||||
// Populates the named_entity member of all IdentifierExpressions in the
|
||||
// subtree rooted at `expression`, whose nearest enclosing scope is
|
||||
// `enclosing_scope`.
|
||||
static void ResolveNamesInExpression(Expression& expression,
|
||||
const StaticScope& enclosing_scope) {
|
||||
switch (expression.kind()) {
|
||||
case ExpressionKind::CallExpression: {
|
||||
auto& call = cast<CallExpression>(expression);
|
||||
ResolveNamesInExpression(call.function(), enclosing_scope);
|
||||
ResolveNamesInExpression(call.argument(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::FunctionTypeLiteral: {
|
||||
auto& fun_type = cast<FunctionTypeLiteral>(expression);
|
||||
ResolveNamesInExpression(fun_type.parameter(), enclosing_scope);
|
||||
ResolveNamesInExpression(fun_type.return_type(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::FieldAccessExpression:
|
||||
ResolveNamesInExpression(
|
||||
cast<FieldAccessExpression>(expression).aggregate(), enclosing_scope);
|
||||
break;
|
||||
case ExpressionKind::IndexExpression: {
|
||||
auto& index = cast<IndexExpression>(expression);
|
||||
ResolveNamesInExpression(index.aggregate(), enclosing_scope);
|
||||
ResolveNamesInExpression(index.offset(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::PrimitiveOperatorExpression:
|
||||
for (Nonnull<Expression*> operand :
|
||||
cast<PrimitiveOperatorExpression>(expression).arguments()) {
|
||||
ResolveNamesInExpression(*operand, enclosing_scope);
|
||||
}
|
||||
break;
|
||||
case ExpressionKind::TupleLiteral:
|
||||
for (Nonnull<Expression*> field :
|
||||
cast<TupleLiteral>(expression).fields()) {
|
||||
ResolveNamesInExpression(*field, enclosing_scope);
|
||||
}
|
||||
break;
|
||||
case ExpressionKind::StructLiteral:
|
||||
for (FieldInitializer& init : cast<StructLiteral>(expression).fields()) {
|
||||
ResolveNamesInExpression(init.expression(), enclosing_scope);
|
||||
}
|
||||
break;
|
||||
case ExpressionKind::StructTypeLiteral:
|
||||
for (FieldInitializer& init :
|
||||
cast<StructTypeLiteral>(expression).fields()) {
|
||||
ResolveNamesInExpression(init.expression(), enclosing_scope);
|
||||
}
|
||||
break;
|
||||
case ExpressionKind::IdentifierExpression: {
|
||||
auto& identifier = cast<IdentifierExpression>(expression);
|
||||
identifier.set_named_entity(
|
||||
enclosing_scope.Resolve(identifier.name(), identifier.source_loc()));
|
||||
break;
|
||||
}
|
||||
case ExpressionKind::IntrinsicExpression:
|
||||
// FIXME implement this once #955 is merged
|
||||
case ExpressionKind::BoolTypeLiteral:
|
||||
case ExpressionKind::BoolLiteral:
|
||||
case ExpressionKind::IntTypeLiteral:
|
||||
case ExpressionKind::ContinuationTypeLiteral:
|
||||
case ExpressionKind::IntLiteral:
|
||||
case ExpressionKind::StringLiteral:
|
||||
case ExpressionKind::StringTypeLiteral:
|
||||
case ExpressionKind::TypeTypeLiteral:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent to ResolveNamesInExpression, but operates on patterns.
|
||||
static void ResolveNamesInPattern(Pattern& pattern,
|
||||
const StaticScope& enclosing_scope) {
|
||||
switch (pattern.kind()) {
|
||||
case PatternKind::BindingPattern:
|
||||
ResolveNamesInPattern(cast<BindingPattern>(pattern).type(),
|
||||
enclosing_scope);
|
||||
break;
|
||||
case PatternKind::TuplePattern:
|
||||
for (Nonnull<Pattern*> field : cast<TuplePattern>(pattern).fields()) {
|
||||
ResolveNamesInPattern(*field, enclosing_scope);
|
||||
}
|
||||
break;
|
||||
case PatternKind::AlternativePattern: {
|
||||
auto& alternative = cast<AlternativePattern>(pattern);
|
||||
ResolveNamesInExpression(alternative.choice_type(), enclosing_scope);
|
||||
ResolveNamesInPattern(alternative.arguments(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
case PatternKind::ExpressionPattern:
|
||||
ResolveNamesInExpression(cast<ExpressionPattern>(pattern).expression(),
|
||||
enclosing_scope);
|
||||
break;
|
||||
case PatternKind::AutoPattern:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Equivalent to ResolveNamesInExpression, but operates on statements.
|
||||
static void ResolveNamesInStatement(Statement& statement,
|
||||
const StaticScope& enclosing_scope) {
|
||||
switch (statement.kind()) {
|
||||
case StatementKind::ExpressionStatement:
|
||||
ResolveNamesInExpression(
|
||||
cast<ExpressionStatement>(statement).expression(), enclosing_scope);
|
||||
break;
|
||||
case StatementKind::Assign: {
|
||||
auto& assign = cast<Assign>(statement);
|
||||
ResolveNamesInExpression(assign.lhs(), enclosing_scope);
|
||||
ResolveNamesInExpression(assign.rhs(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
case StatementKind::VariableDefinition: {
|
||||
auto& def = cast<VariableDefinition>(statement);
|
||||
ResolveNamesInPattern(def.pattern(), enclosing_scope);
|
||||
ResolveNamesInExpression(def.init(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
case StatementKind::If: {
|
||||
auto& if_stmt = cast<If>(statement);
|
||||
ResolveNamesInExpression(if_stmt.condition(), enclosing_scope);
|
||||
ResolveNamesInStatement(if_stmt.then_block(), enclosing_scope);
|
||||
if (if_stmt.else_block().has_value()) {
|
||||
ResolveNamesInStatement(**if_stmt.else_block(), enclosing_scope);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case StatementKind::Return:
|
||||
ResolveNamesInExpression(cast<Return>(statement).expression(),
|
||||
enclosing_scope);
|
||||
break;
|
||||
case StatementKind::Block: {
|
||||
// TODO: this will resolve usages to declarations that occur later in
|
||||
// the block. Figure out how to avoid that.
|
||||
auto& block = cast<Block>(statement);
|
||||
for (Nonnull<Statement*> sub_statement : block.statements()) {
|
||||
ResolveNamesInStatement(*sub_statement, block.static_scope());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case StatementKind::While: {
|
||||
auto& while_stmt = cast<While>(statement);
|
||||
ResolveNamesInExpression(while_stmt.condition(), enclosing_scope);
|
||||
ResolveNamesInStatement(while_stmt.body(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
case StatementKind::Match: {
|
||||
auto& match = cast<Match>(statement);
|
||||
ResolveNamesInExpression(match.expression(), enclosing_scope);
|
||||
for (Match::Clause& clause : match.clauses()) {
|
||||
ResolveNamesInPattern(clause.pattern(), clause.static_scope());
|
||||
ResolveNamesInStatement(clause.statement(), clause.static_scope());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case StatementKind::Continuation:
|
||||
ResolveNamesInStatement(cast<Continuation>(statement).body(),
|
||||
enclosing_scope);
|
||||
break;
|
||||
case StatementKind::Run:
|
||||
ResolveNamesInExpression(cast<Run>(statement).argument(),
|
||||
enclosing_scope);
|
||||
break;
|
||||
case StatementKind::Await:
|
||||
case StatementKind::Break:
|
||||
case StatementKind::Continue:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Recurses through a declaration to find and resolve IdentifierExpressions
|
||||
// using declared_names.
|
||||
void ResolveNamesInDeclaration(Declaration& declaration,
|
||||
const StaticScope& static_scope) {
|
||||
const StaticScope& enclosing_scope) {
|
||||
switch (declaration.kind()) {
|
||||
case DeclarationKind::FunctionDeclaration:
|
||||
case DeclarationKind::ClassDeclaration:
|
||||
case DeclarationKind::ChoiceDeclaration:
|
||||
case DeclarationKind::VariableDeclaration:
|
||||
case DeclarationKind::FunctionDeclaration: {
|
||||
auto& function = cast<FunctionDeclaration>(declaration);
|
||||
for (Nonnull<GenericBinding*> binding : function.deduced_parameters()) {
|
||||
ResolveNamesInExpression(binding->type(), function.static_scope());
|
||||
}
|
||||
ResolveNamesInPattern(function.param_pattern(), function.static_scope());
|
||||
if (function.return_term().type_expression().has_value()) {
|
||||
ResolveNamesInExpression(**function.return_term().type_expression(),
|
||||
function.static_scope());
|
||||
}
|
||||
if (function.body().has_value()) {
|
||||
ResolveNamesInStatement(**function.body(), function.static_scope());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DeclarationKind::ClassDeclaration: {
|
||||
auto& class_decl = cast<ClassDeclaration>(declaration);
|
||||
for (Nonnull<Member*> member : class_decl.members()) {
|
||||
switch (member->kind()) {
|
||||
case MemberKind::FieldMember:
|
||||
ResolveNamesInPattern(cast<FieldMember>(member)->binding(),
|
||||
class_decl.static_scope());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DeclarationKind::ChoiceDeclaration: {
|
||||
auto& choice = cast<ChoiceDeclaration>(declaration);
|
||||
for (Nonnull<AlternativeSignature*> alternative : choice.alternatives()) {
|
||||
ResolveNamesInExpression(alternative->signature(),
|
||||
choice.static_scope());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
auto& var = cast<VariableDeclaration>(declaration);
|
||||
ResolveNamesInPattern(var.binding(), enclosing_scope);
|
||||
ResolveNamesInExpression(var.initializer(), enclosing_scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +401,9 @@ void ResolveNames(Arena* arena, AST& ast) {
|
||||
for (auto declaration : ast.declarations) {
|
||||
ResolveNamesInDeclaration(*declaration, ast.static_scope);
|
||||
}
|
||||
if (ast.main_call.has_value()) {
|
||||
ResolveNamesInExpression(**ast.main_call, ast.static_scope);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
Reference in New Issue
Block a user