1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
// Copyright (c) 2016-2021 Fabian Schuiki
//! A resolved syntax tree.
//!
//! This module implements the RST, which is an unambiguous representation of
//! the AST. This is achieved by resolving AST ambiguities through name lookups.
use crate::crate_prelude::*;
use crate::{ast, ast_map::AstNode, common::arenas::Alloc, resolver::DefNode};
/// A node kind.
///
/// Nodes in the AST can be queried for their kind, which yields this enum.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Kind {
/// This node is a value.
Value,
/// This node is a type.
Type,
}
/// Determine the kind of a node.
#[moore_derive::query]
pub(crate) fn disamb_kind<'a>(
_cx: &impl Context<'a>,
Ref(ast): Ref<'a, dyn ast::AnyNode<'a>>,
) -> Kind {
match ast.as_all() {
ast::AllNode::Type(..) | ast::AllNode::ParamTypeDecl(..) | ast::AllNode::Typedef(..) => {
Kind::Type
}
_ => Kind::Value,
}
}
/// Disambiguate a type or expression.
#[moore_derive::query]
pub(crate) fn disamb_type_or_expr<'a>(
cx: &impl Context<'a>,
Ref(ast): Ref<'a, ast::TypeOrExpr<'a>>,
) -> Result<&'a ast::TypeOrExpr<'a>> {
match *ast {
ast::TypeOrExpr::Expr(expr) => match expr.data {
ast::IdentExpr(n) => {
let loc = cx.scope_location(expr);
let binding = cx.resolve_local_or_error(n, loc, false)?;
match cx.disamb_kind(Ref(&binding.node)) {
Kind::Value => Ok(ast),
Kind::Type => {
let ty = cx.arena().alloc(ast::Type::new(
expr.span,
ast::TypeData {
kind: ast::TypeKind::new(expr.span, ast::NamedType(n)),
sign: ast::TypeSign::None,
dims: vec![],
},
));
ty.link_attach(expr, expr.order());
cx.register_ast(ty);
cx.map_ast_with_parent(AstNode::Type(ty), ty.id());
Ok(cx.arena().alloc(ast::TypeOrExpr::Type(ty)))
}
}
}
// TODO: The following is an ugly duplicate of code which also lives
// in typeck. This whole scoped name resolution thing should be a
// distinct RST query which returns something like a rst::Path.
ast::ScopeExpr(ref target, name) => match target.data {
ast::IdentExpr(pkg_name) => {
// Resolve the name.
let loc = cx.scope_location(target.as_ref());
let def = match cx.resolve_local_or_error(pkg_name, loc, false) {
Ok(def) => def,
_ => return Err(()),
};
// See if the binding is a package.
let pkg = match def.node {
DefNode::Ast(node) => node.as_all().get_package(),
_ => None,
};
let pkg = match pkg {
Some(x) => x,
None => {
cx.emit(
DiagBuilder2::error(format!("`{}` is not a package", pkg_name))
.span(pkg_name.span)
.add_note(format!("`{}` was declared here:", pkg_name))
.span(def.node.span()),
);
return Err(());
}
};
// Resolve the type name within the package.
let def = match cx.resolve_hierarchical_or_error(name, pkg) {
Ok(def) => def,
_ => return Err(()),
};
match cx.disamb_kind(Ref(&def.node)) {
Kind::Value => Ok(ast),
Kind::Type => {
let target_ty = ast::Type::new(
target.span,
ast::TypeData {
kind: ast::TypeKind::new(expr.span, ast::NamedType(pkg_name)),
sign: ast::TypeSign::None,
dims: vec![],
},
);
let ty = cx.arena().alloc(ast::Type::new(
expr.span,
ast::TypeData {
kind: ast::TypeKind::new(
expr.span,
ast::ScopedType {
ty: Box::new(target_ty),
member: false,
name,
},
),
sign: ast::TypeSign::None,
dims: vec![],
},
));
ty.link_attach(expr, expr.order());
cx.register_ast(ty);
cx.map_ast_with_parent(AstNode::Type(ty), ty.id());
Ok(cx.arena().alloc(ast::TypeOrExpr::Type(ty)))
}
}
}
_ => {
cx.emit(
DiagBuilder2::error(format!(
"`{}` is not a package",
expr.span().extract()
))
.span(expr.span()),
);
return Err(());
}
},
_ => Ok(ast),
},
ast::TypeOrExpr::Type(_ty) => Ok(ast),
}
}