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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// 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),
}
}
/// Resolve the type/name ambiguity in a subroutine port.
#[moore_derive::query]
pub(crate) fn resolve_subroutine_port_ty_name<'a>(
cx: &impl Context<'a>,
Ref(node): Ref<'a, ast::SubroutinePort<'a>>,
) -> &'a (ast::Type<'a>, Option<ast::SubroutinePortName<'a>>) {
let xs = match &node.ty_name {
ast::Ambiguous::Unique(x) => return x,
ast::Ambiguous::Ambiguous(xs) => xs,
};
debug!("Resolving ambiguity in {:1?}", node);
// Let's first try to resolve type names.
for x in xs {
let name = match x.0.kind.data {
ast::NamedType(x) => x,
_ => continue,
};
trace!(" - Trying type name {}", name);
let binding = match cx
.resolve_local(name.value, cx.scope_location(node), false)
.unwrap_or(None)
{
Some(x) => x,
None => continue,
};
trace!(" - Resolved to {:?}", binding);
match cx.disamb_kind(Ref(&binding.node)) {
Kind::Type => {
trace!(" - Resolved as {:?}", x);
return x;
}
_ => continue,
}
}
// If we arrive here, named types did not match. Return whatever is left.
for x in xs {
if x.1.is_some() {
trace!(" - Resolved as {:?}", x);
return x;
}
}
bug_span!(node.span, cx, "unable to resolve ambiguity");
}