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:
Geoff Romer
2021-11-30 13:33:54 -08:00
committed by GitHub
co-authored by Jon Meow
parent dc5e62fc7a
commit 17e0a1afb9
12 changed files with 347 additions and 22 deletions
@@ -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