diff --git a/dag/extdeps/languages/dag/syntax.dag b/dag/extdeps/languages/dag/syntax.dag index fe03057137e..dd5d7986471 100644 --- a/dag/extdeps/languages/dag/syntax.dag +++ b/dag/extdeps/languages/dag/syntax.dag @@ -22,6 +22,9 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } data dag_item_forms: List = [ + ItemForm { kind: OtherForm, keyword: "alias", has_type_params: false, has_params: false, + has_return_type: false, return_required: false, + has_uses: false, body_kind: AliasBody }, ItemForm { kind: TypeAliasForm, keyword: "type", has_type_params: true, has_params: false, has_return_type: false, return_required: false, has_uses: false, body_kind: TypeBody }, @@ -56,7 +59,7 @@ data dag_keyword_literals: Map = { } data dag_keyword_set: Map = { - "module": true, "import": true, "type": true, "fn": true, "func": true, + "module": true, "import": true, "alias": true, "type": true, "fn": true, "func": true, "resource": true, "service": true, "data": true, "interface": true, "pipeline": true, "profile": true, "pattern": true, "let": true, "return": true, "match": true, "if": true, "then": true, "else": true, diff --git a/dag/std/syntax.dag b/dag/std/syntax.dag index 77d4aae030e..111fb91073e 100644 --- a/dag/std/syntax.dag +++ b/dag/std/syntax.dag @@ -22,6 +22,7 @@ type BodyKind | NoBody | ServiceBody | ResourceBody + | AliasBody type ItemFormKind = FuncForm diff --git a/src/v1/02_parse.dag b/src/v1/02_parse.dag index 50f10e65eee..243997d60dc 100644 --- a/src/v1/02_parse.dag +++ b/src/v1/02_parse.dag @@ -1004,7 +1004,7 @@ fn parse_item(tokens: TokenStream, ctx: ParseContext) -> ItemResult { let form = find_item_form(forms: dag_syntax_spec.item_forms, keyword: kw) match form { Present { value: f } => parse_item_by_form(tokens: tokens, ctx: ctx, form: f) - Absent => ItemResult { item: Node { name: "", span: span, ident_span: Present { value: span }, children: [], params: [], inferred: none, return_cardinality: Required, uses: [], body: none, connective: NoConnective, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData }, tokens: tokens, ctx: ctx, err: Present { value: parse_error(msg: "expected item declaration (type, fn, func, service, resource, data, extern, pattern, interface)", span: span) } } + Absent => ItemResult { item: Node { name: "", span: span, ident_span: Present { value: span }, children: [], params: [], inferred: none, return_cardinality: Required, uses: [], body: none, connective: NoConnective, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData }, tokens: tokens, ctx: ctx, err: Present { value: parse_error(msg: "expected item declaration (alias, type, fn, func, service, resource, data, extern, pattern, interface)", span: span) } } } } @@ -1080,6 +1080,7 @@ fn parse_item_by_form(tokens: TokenStream, ctx: ParseContext, form: ItemForm) -> ServiceBody => parse_service_after_kw(tokens: tokens, ctx: ctx, start_span: start_span) ResourceBody => parse_resource_after_kw(tokens: tokens, ctx: ctx, start_span: start_span) ValueBody => parse_data_after_kw(tokens: tokens, ctx: ctx, start_span: start_span) + AliasBody => parse_alias_after_kw(tokens: tokens, ctx: ctx, start_span: start_span) NoBody => { let prefix = parse_item_prefix(tokens: tokens, ctx: ctx, form: form) if has_err(err: prefix.err) { return ItemResult { item: dummy, tokens: prefix.tokens, ctx: prefix.ctx, err: prefix.err } } @@ -2973,6 +2974,44 @@ fn parse_data_def(tokens: TokenStream, ctx: ParseContext) -> ItemResult { parse_data_after_kw(tokens: r.tokens, ctx: ctx, start_span: start_span) } +fn parse_alias_after_kw(tokens: TokenStream, ctx: ParseContext, start_span: SourceSpan) -> ItemResult { + let dummy = Node { name: "", span: start_span, ident_span: none, children: [], params: [], inferred: none, return_cardinality: Required, uses: [], body: none, connective: NoConnective, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData } + + let r = expect_ident(tokens: tokens) + if has_err(err: r.err) { return ItemResult { item: dummy, tokens: r.tokens, ctx: ctx, err: r.err } } + let name = r.name + let name_span = r.span + let named_dummy = Node { name: name, span: start_span, ident_span: Present { value: name_span }, children: [], params: [], inferred: none, return_cardinality: Required, uses: [], body: none, connective: NoConnective, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData } + + let r = expect(tokens: r.tokens, expected: ExpectEq) + if has_err(err: r.err) { return ItemResult { item: named_dummy, tokens: r.tokens, ctx: ctx, err: r.err } } + + let r = parse_dotted_ident(tokens: r.tokens) + if has_err(err: r.err) { return ItemResult { item: named_dummy, tokens: r.tokens, ctx: ctx, err: r.err } } + let target_path = r.name + + let target_prop = make_field_init_node( + name: "namespace_alias_target", + value: make_expr_node( + expr_data: ExprLiteral { value: LitStr { value: target_path } }, + children: [], + inferred: none, + span: r.span + ), + span: start_span, + name_span: no_span() + ) + + let item = Node { + name: name, span: start_span, ident_span: Present { value: name_span }, children: [], + params: [], inferred: none, return_cardinality: Required, uses: [], + body: none, connective: NoConnective, transport: none, + properties: [target_prop], type_annotation: none, + is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData + } + ItemResult { item: item, tokens: skip_newlines(tokens: r.tokens), ctx: ctx, err: none } +} + fn parse_data_after_kw(tokens: TokenStream, ctx: ParseContext, start_span: SourceSpan) -> ItemResult { let dummy = Node { name: "", span: start_span, ident_span: none, children: [], params: [], inferred: none, return_cardinality: Required, uses: [], body: none, connective: NoConnective, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData } diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index c0fe78666b2..d93c8615b46 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -5,7 +5,7 @@ import std.coercion { dag_can_cast, is_dag_cast_domain_type } import v1.std.core { Node, InternTable, intern, intern_str, empty_intern_table, - authored_name_at, generic_param_name_at, NewlineIndex, find_child_named, has_child_named, build_newline_index, + authored_name_at, generic_param_name_at, NewlineIndex, find_child_named, find_property_string, has_child_named, build_newline_index, module_node, module_imports, module_items, import_is_all, import_specific_names_at, make_param_node, param_node_name_at, param_node_type_expr, field_node_type_expr, field_node_name_at, @@ -484,6 +484,29 @@ fn namespace_root_from_properties(properties: List, name: String, source_i } } +fn namespace_alias_target_path(item: Node, source_indices: Map) -> String? { + find_property_string(props: item.properties, prop_name: "namespace_alias_target", source_indices: source_indices) +} + +fn is_namespace_alias_item(item: Node, source_indices: Map) -> Bool { + match namespace_alias_target_path(item: item, source_indices: source_indices) { + Present { value: _ } => true + Absent => false + } +} + +fn namespace_alias_binding_for_target( + item: Node, + target_node: Node, + source_indices: Map +) -> TypeBinding { + TypeBinding { + name: authored_name_at(source_indices: source_indices, node: item), + resolved: target_node, + provenance: SubValueUnknown + } +} + fn expr_span(texpr: Node) -> SourceSpan { texpr.span } @@ -6203,6 +6226,9 @@ fn build_module_interface( fn local_binding_for_item(item: Node, source_indices: Map) -> TypeBinding? { + if is_namespace_alias_item(item: item, source_indices: source_indices) { + none + } else { let has_structure = item.connective != NoConnective if has_structure { let type_node = Node { @@ -6248,6 +6274,7 @@ fn local_binding_for_item(item: Node, source_indices: Map) } else { none } + } } fn symbol_index_insert_item( @@ -6256,14 +6283,34 @@ fn symbol_index_insert_item( item: Node, source_indices: Map ) -> SymbolIndex { - let with_decl = match local_binding_for_item(item: item, source_indices: source_indices) { - Absent => index - Present { value: binding } => - symbol_index_insert_decl( - index: index, - module_path: module_path, - binding: binding - ) + let with_decl = if is_namespace_alias_item(item: item, source_indices: source_indices) { + match namespace_alias_target_path(item: item, source_indices: source_indices) { + Absent => index + Present { value: target_path } => + match symbol_index_lookup(index: index, qualified_name: target_path) { + Absent => index + Present { value: target_node } => + symbol_index_insert_decl( + index: index, + module_path: module_path, + binding: namespace_alias_binding_for_target( + item: item, + target_node: target_node, + source_indices: source_indices + ) + ) + } + } + } else { + match local_binding_for_item(item: item, source_indices: source_indices) { + Absent => index + Present { value: binding } => + symbol_index_insert_decl( + index: index, + module_path: module_path, + binding: binding + ) + } } if item.transport != none && item.children |> count > 0 { symbol_index_insert_service( @@ -6784,11 +6831,40 @@ fn build_type_env(module: ResolvedModule, parent_index: Map ) let scope_parents = concat(import_parents, [kernel]) let import_diags = flat_map(module.resolved_imports, imp => match map_get(parent_index, imp.module_path) { Present { value: _ } => [] Absent => [make_error_node(diagnostic: InternalError { message: concat("missing parent environment for imported module '", imp.module_path, "' while typechecking '", module_name_str, "'"), span: imp.target_module.value.span }, module_name: module_name_str)] }) + let namespace_alias_diags = flat_map(module_items(n: module.module), item => + if is_namespace_alias_item(item: item, source_indices: source_indices) { + match namespace_alias_target_path(item: item, source_indices: source_indices) { + Absent => [] + Present { value: target_path } => + match symbol_index_lookup(index: symbol_index, qualified_name: target_path) { + Present { value: _ } => [] + Absent => [make_error_node(diagnostic: UnresolvedType { name: target_path, span: item.span }, module_name: module_name_str)] + } + } + } else { [] } + ) let local_bindings = fold(module_items(n: module.module), init: empty_map(), f: (acc, item) => - match local_binding_for_item(item: item, source_indices: source_indices) { - Present { value: binding } => map_insert(acc, intern(table: intern_table, s: binding.name).id, binding) - Absent => acc + if is_namespace_alias_item(item: item, source_indices: source_indices) { + match namespace_alias_target_path(item: item, source_indices: source_indices) { + Absent => acc + Present { value: target_path } => + match symbol_index_lookup(index: symbol_index, qualified_name: target_path) { + Absent => acc + Present { value: target_node } => + let binding = namespace_alias_binding_for_target( + item: item, + target_node: target_node, + source_indices: source_indices + ) + map_insert(acc, intern(table: intern_table, s: binding.name).id, binding) + } + } + } else { + match local_binding_for_item(item: item, source_indices: source_indices) { + Present { value: binding } => map_insert(acc, intern(table: intern_table, s: binding.name).id, binding) + Absent => acc + } } ) @@ -6887,7 +6963,7 @@ fn build_type_env(module: ResolvedModule, parent_index: Map BuildTypeEnvResult { env: final_env, cache: type_env_cache, - diagnostics: concat(import_diags, resolved_diags), + diagnostics: concat(concat(import_diags, namespace_alias_diags), resolved_diags), binding_forks: binding_forks } } @@ -6917,6 +6993,9 @@ fn build_type_env_unresolved(module: ResolvedModule, parent_index: Map + if is_namespace_alias_item(item: item, source_indices: source_indices) { + acc + } else { let item_ident = intern(table: intern_table, s: authored_name_at(source_indices: source_indices, node: item)).id let has_structure = item.connective != NoConnective if has_structure { @@ -6933,6 +7012,7 @@ fn build_type_env_unresolved(module: ResolvedModule, parent_index: Map Rc>> { thread_local! { static CACHED: Rc>> = { Rc::new(vec![Rc::new(ItemForm { + kind: ItemFormKind::OtherForm, + keyword: "alias".to_string(), + has_type_params: false, + has_params: false, + has_return_type: false, + return_required: false, + has_uses: false, + body_kind: BodyKind::AliasBody, + }), Rc::new(ItemForm { kind: ItemFormKind::TypeAliasForm, keyword: "type".to_string(), has_type_params: true, @@ -145,6 +154,7 @@ pub fn dag_keyword_set() -> Rc> { let mut __m = HashMap::new(); __m.insert("module".to_string(), true); __m.insert("import".to_string(), true); + __m.insert("alias".to_string(), true); __m.insert("type".to_string(), true); __m.insert("fn".to_string(), true); __m.insert("func".to_string(), true); diff --git a/src/v1/stage0/src/std_syntax.rs b/src/v1/stage0/src/std_syntax.rs index 8ec3bae13c1..d045ed74a05 100644 --- a/src/v1/stage0/src/std_syntax.rs +++ b/src/v1/stage0/src/std_syntax.rs @@ -60,6 +60,7 @@ pub enum BodyKind { NoBody, ServiceBody, ResourceBody, + AliasBody, } #[derive( @@ -201,6 +202,8 @@ pub struct ServiceBody; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct ResourceBody; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct AliasBody; +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct FuncForm; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct StructForm; diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 5c5fcd55975..f472cd86940 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -158,21 +158,22 @@ pub use crate::v1_std_core::{ expr_has_non_tail_self_call, expr_has_self_call, expr_method_name_at, expr_var_name_at, field_access_base, field_access_field_at, field_access_spine, field_binding_name_at, field_binding_pattern, field_init_node_name_at, field_init_node_value, field_node_name_at, - field_node_type_expr, find_child_named, float_type, foreach_body, foreach_collection, - foreach_variable_at, generic_param_name_at, has_child_named, has_inferred, if_condition, - if_else_branch, if_then_branch, import_is_all, import_specific_names_at, index_base, - index_expr, int_type, intern, intern_str, is_child_accessor_in_model, is_compiler_error, - is_container_type, is_error_diagnostic, is_kernel_type, is_property_contraction, - is_tree_size_reducing, kernel_type_set, lambda_body, lambda_param_names_at, - let_binding_name_at, let_body, let_value, local_transport_node, make_arg_node, make_arm_node, - make_error_node, make_expr_error_node, make_expr_node, make_field_binding_node, - make_field_init_node, make_interp_part_node, make_named_expr_node, make_param_node, make_span, - make_text_part_node, make_transport_node, map_children, match_arm_nodes, match_scrutinee, - method_arg_nodes, method_receiver, module_imports, module_items, module_node, no_span, - node_name_span, none_type, param_node_name_at, param_node_type_expr, qualified_last_segment, - record_lit_type_name_at, resource_use_name_at, resource_use_resource, return_value, slice_base, - slice_end, slice_start, string_type, type_name_compatible, unaryop_operand, unit_type, - with_optional_cardinality, with_required_cardinality, + field_node_type_expr, find_child_named, find_property_string, float_type, foreach_body, + foreach_collection, foreach_variable_at, generic_param_name_at, has_child_named, has_inferred, + if_condition, if_else_branch, if_then_branch, import_is_all, import_specific_names_at, + index_base, index_expr, int_type, intern, intern_str, is_child_accessor_in_model, + is_compiler_error, is_container_type, is_error_diagnostic, is_kernel_type, + is_property_contraction, is_tree_size_reducing, kernel_type_set, lambda_body, + lambda_param_names_at, let_binding_name_at, let_body, let_value, local_transport_node, + make_arg_node, make_arm_node, make_error_node, make_expr_error_node, make_expr_node, + make_field_binding_node, make_field_init_node, make_interp_part_node, make_named_expr_node, + make_param_node, make_span, make_text_part_node, make_transport_node, map_children, + match_arm_nodes, match_scrutinee, method_arg_nodes, method_receiver, module_imports, + module_items, module_node, no_span, node_name_span, none_type, param_node_name_at, + param_node_type_expr, qualified_last_segment, record_lit_type_name_at, resource_use_name_at, + resource_use_resource, return_value, slice_base, slice_end, slice_start, string_type, + type_name_compatible, unaryop_operand, unit_type, with_optional_cardinality, + with_required_cardinality, }; pub use crate::v1_std_core::{ CallSemantics, Cardinality, CompilerDiagnostic, Connective, DeclaredFuncEnv, DeclaredFuncSig, @@ -787,6 +788,39 @@ pub fn namespace_root_from_properties( } } +pub fn namespace_alias_target_path( + item: Rc, + source_indices: Rc>>, +) -> Option { + find_property_string( + item.properties.clone(), + "namespace_alias_target".to_string(), + source_indices.clone(), + ) +} + +pub fn is_namespace_alias_item( + item: Rc, + source_indices: Rc>>, +) -> bool { + match namespace_alias_target_path(item.clone(), source_indices.clone()) { + Some(_) => true, + None => false, + } +} + +pub fn namespace_alias_binding_for_target( + item: Rc, + target_node: Rc, + source_indices: Rc>>, +) -> Rc { + Rc::new(TypeBinding { + name: authored_name_at(source_indices.clone(), item.clone()), + resolved: target_node.clone(), + provenance: Rc::new(SubValueRelation::SubValueUnknown), + }) +} + pub fn expr_span(texpr: Rc) -> Rc { texpr.span.clone() } @@ -13222,53 +13256,27 @@ pub fn local_binding_for_item( item: Rc, source_indices: Rc>>, ) -> Option> { - { - let has_structure = (item.connective.clone() != Connective::NoConnective); - if has_structure.clone() { - { - let type_node = Rc::new(Node { - name: item.name.clone(), - span: item.span.clone(), - ident_span: item.ident_span.clone(), - children: item.children.clone(), - connective: item.connective.clone(), - params: item.params.clone(), - inferred: None, - return_cardinality: item.return_cardinality.clone(), - uses: Rc::new(vec![]), - body: None, - transport: None, - properties: item.properties.clone(), - type_annotation: None, - is_self_recursive: false, - has_non_tail_self_call: false, - match_pattern: None, - expr_data: Rc::new(ExprData::NoExprData), - ident: None, - }); - Some(Rc::new(TypeBinding { - name: authored_name_at(source_indices.clone(), item.clone()), - resolved: type_node.clone(), - provenance: Rc::new(SubValueRelation::SubValueUnknown), - })) - } - } else { - if ((item.body.clone() != None) && (item.transport.clone() == None)) { + if is_namespace_alias_item(item.clone(), source_indices.clone()) { + None + } else { + { + let has_structure = (item.connective.clone() != Connective::NoConnective); + if has_structure.clone() { { - let fn_node = Rc::new(Node { + let type_node = Rc::new(Node { name: item.name.clone(), span: item.span.clone(), ident_span: item.ident_span.clone(), - children: Rc::new(vec![]), - connective: Connective::NoConnective, + children: item.children.clone(), + connective: item.connective.clone(), params: item.params.clone(), - inferred: item.inferred.clone(), + inferred: None, return_cardinality: item.return_cardinality.clone(), uses: Rc::new(vec![]), body: None, transport: None, - properties: Rc::new(vec![]), - type_annotation: item.type_annotation.clone(), + properties: item.properties.clone(), + type_annotation: None, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: None, @@ -13277,29 +13285,27 @@ pub fn local_binding_for_item( }); Some(Rc::new(TypeBinding { name: authored_name_at(source_indices.clone(), item.clone()), - resolved: fn_node.clone(), + resolved: type_node.clone(), provenance: Rc::new(SubValueRelation::SubValueUnknown), })) } } else { - if (((item.inferred.clone() != None) && ((item.params.clone().len() as i64) == 0)) - && (item.body.clone() == None)) - { + if ((item.body.clone() != None) && (item.transport.clone() == None)) { { - let alias_node = Rc::new(Node { + let fn_node = Rc::new(Node { name: item.name.clone(), span: item.span.clone(), ident_span: item.ident_span.clone(), children: Rc::new(vec![]), connective: Connective::NoConnective, - params: Rc::new(vec![]), + params: item.params.clone(), inferred: item.inferred.clone(), return_cardinality: item.return_cardinality.clone(), uses: Rc::new(vec![]), body: None, transport: None, properties: Rc::new(vec![]), - type_annotation: None, + type_annotation: item.type_annotation.clone(), is_self_recursive: false, has_non_tail_self_call: false, match_pattern: None, @@ -13308,72 +13314,108 @@ pub fn local_binding_for_item( }); Some(Rc::new(TypeBinding { name: authored_name_at(source_indices.clone(), item.clone()), - resolved: alias_node.clone(), + resolved: fn_node.clone(), provenance: Rc::new(SubValueRelation::SubValueUnknown), })) } } else { - if ((item.transport.clone() == None) - && ((item.children.clone().len() as i64) > 0)) + if (((item.inferred.clone() != None) + && ((item.params.clone().len() as i64) == 0)) + && (item.body.clone() == None)) { { - let ref_node = nominal_ref_node( - authored_name_at(source_indices.clone(), item.clone()), - item.span.clone(), - item.ident_span.clone(), - ); + let alias_node = Rc::new(Node { + name: item.name.clone(), + span: item.span.clone(), + ident_span: item.ident_span.clone(), + children: Rc::new(vec![]), + connective: Connective::NoConnective, + params: Rc::new(vec![]), + inferred: item.inferred.clone(), + return_cardinality: item.return_cardinality.clone(), + uses: Rc::new(vec![]), + body: None, + transport: None, + properties: Rc::new(vec![]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + }); Some(Rc::new(TypeBinding { name: authored_name_at(source_indices.clone(), item.clone()), - resolved: ref_node.clone(), + resolved: alias_node.clone(), provenance: Rc::new(SubValueRelation::SubValueUnknown), })) } } else { - if (((((item.params.clone().len() as i64) > 0) - && (item.connective.clone() == Connective::NoConnective)) - && (item.body.clone() == None)) - && (item.transport.clone() == None)) + if ((item.transport.clone() == None) + && ((item.children.clone().len() as i64) > 0)) { { - let bare_node = Rc::new(Node { - name: item.name.clone(), - span: item.span.clone(), - ident_span: item.ident_span.clone(), - children: Rc::new(vec![]), - connective: Connective::NoConnective, - params: item.params.clone(), - inferred: item.inferred.clone(), - return_cardinality: item.return_cardinality.clone(), - uses: Rc::new(vec![]), - body: None, - transport: None, - properties: Rc::new(vec![]), - type_annotation: None, - is_self_recursive: false, - has_non_tail_self_call: false, - match_pattern: None, - expr_data: Rc::new(ExprData::NoExprData), - ident: None, - }); + let ref_node = nominal_ref_node( + authored_name_at(source_indices.clone(), item.clone()), + item.span.clone(), + item.ident_span.clone(), + ); Some(Rc::new(TypeBinding { name: authored_name_at(source_indices.clone(), item.clone()), - resolved: bare_node.clone(), + resolved: ref_node.clone(), provenance: Rc::new(SubValueRelation::SubValueUnknown), })) } } else { - if ((((((item.properties.clone().len() as i64) > 0) + if (((((item.params.clone().len() as i64) > 0) && (item.connective.clone() == Connective::NoConnective)) + && (item.body.clone() == None)) && (item.transport.clone() == None)) - && (item.inferred.clone() == None)) - && ((item.params.clone().len() as i64) == 0)) { - Some(nominal_type_binding(authored_name_at( - source_indices.clone(), - item.clone(), - ))) + { + let bare_node = Rc::new(Node { + name: item.name.clone(), + span: item.span.clone(), + ident_span: item.ident_span.clone(), + children: Rc::new(vec![]), + connective: Connective::NoConnective, + params: item.params.clone(), + inferred: item.inferred.clone(), + return_cardinality: item.return_cardinality.clone(), + uses: Rc::new(vec![]), + body: None, + transport: None, + properties: Rc::new(vec![]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + }); + Some(Rc::new(TypeBinding { + name: authored_name_at( + source_indices.clone(), + item.clone(), + ), + resolved: bare_node.clone(), + provenance: Rc::new(SubValueRelation::SubValueUnknown), + })) + } } else { - None + if ((((((item.properties.clone().len() as i64) > 0) + && (item.connective.clone() == Connective::NoConnective)) + && (item.transport.clone() == None)) + && (item.inferred.clone() == None)) + && ((item.params.clone().len() as i64) == 0)) + { + Some(nominal_type_binding(authored_name_at( + source_indices.clone(), + item.clone(), + ))) + } else { + None + } } } } @@ -13390,10 +13432,30 @@ pub fn symbol_index_insert_item( source_indices: Rc>>, ) -> Rc { { - let with_decl = match local_binding_for_item(item.clone(), source_indices.clone()) { - None => index.clone(), - Some(binding) => { - symbol_index_insert_decl(index.clone(), module_path.clone(), binding.clone()) + let with_decl = if is_namespace_alias_item(item.clone(), source_indices.clone()) { + match namespace_alias_target_path(item.clone(), source_indices.clone()) { + None => index.clone(), + Some(target_path) => { + match symbol_index_lookup(index.clone(), target_path.clone()) { + None => index.clone(), + Some(target_node) => symbol_index_insert_decl( + index.clone(), + module_path.clone(), + namespace_alias_binding_for_target( + item.clone(), + target_node.clone(), + source_indices.clone(), + ), + ), + } + } + } + } else { + match local_binding_for_item(item.clone(), source_indices.clone()) { + None => index.clone(), + Some(binding) => { + symbol_index_insert_decl(index.clone(), module_path.clone(), binding.clone()) + } } }; if ((item.transport.clone() != None) && ((item.children.clone().len() as i64) > 0)) { @@ -14763,20 +14825,74 @@ pub fn build_type_env( } __result }); + let namespace_alias_diags = Rc::new({ + let mut __result = Vec::new(); + for item in module_items(module.module.clone()).iter().cloned() { + __result.extend( + (*if is_namespace_alias_item(item.clone(), source_indices.clone()) { + match namespace_alias_target_path(item.clone(), source_indices.clone()) { + None => Rc::new(vec![]), + Some(target_path) => { + match symbol_index_lookup(symbol_index.clone(), target_path.clone()) + { + Some(_) => Rc::new(vec![]), + None => Rc::new(vec![make_error_node( + Rc::new(CompilerDiagnostic::UnresolvedType { + name: target_path.clone(), + span: item.span.clone(), + }), + module_name_str.clone(), + )]), + } + } + } + } else { + Rc::new(vec![]) + }) + .iter() + .cloned(), + ); + } + __result + }); let local_bindings = module_items(module.module.clone()).iter().cloned().fold( v1_rt::rc_empty_map::>(), - |acc: Rc>>, item: Rc| match local_binding_for_item( - item.clone(), - source_indices.clone(), - ) { - Some(binding) => v1_rt::rc_map_insert( - acc.clone(), - intern(intern_table.clone(), binding.name.clone()) - .id - .clone(), - binding.clone(), - ), - None => acc.clone(), + |acc: Rc>>, item: Rc| { + if is_namespace_alias_item(item.clone(), source_indices.clone()) { + match namespace_alias_target_path(item.clone(), source_indices.clone()) { + None => acc.clone(), + Some(target_path) => { + match symbol_index_lookup(symbol_index.clone(), target_path.clone()) { + None => acc.clone(), + Some(target_node) => { + let binding = namespace_alias_binding_for_target( + item.clone(), + target_node.clone(), + source_indices.clone(), + ); + v1_rt::rc_map_insert( + acc.clone(), + intern(intern_table.clone(), binding.name.clone()) + .id + .clone(), + binding.clone(), + ) + } + } + } + } + } else { + match local_binding_for_item(item.clone(), source_indices.clone()) { + Some(binding) => v1_rt::rc_map_insert( + acc.clone(), + intern(intern_table.clone(), binding.name.clone()) + .id + .clone(), + binding.clone(), + ), + None => acc.clone(), + } + } }, ); let param_bindings = module_items(module.module.clone()).iter().cloned().fold( @@ -15069,7 +15185,10 @@ pub fn build_type_env( Rc::new(BuildTypeEnvResult { env: final_env.clone(), cache: type_env_cache.clone(), - diagnostics: v1_rt::concat(import_diags.clone(), resolved_diags.clone()), + diagnostics: v1_rt::concat( + v1_rt::concat(import_diags.clone(), namespace_alias_diags.clone()), + resolved_diags.clone(), + ), binding_forks: binding_forks.clone(), }) } @@ -15260,91 +15379,39 @@ pub fn build_type_env_unresolved( let local_bindings = module_items(module.module.clone()).iter().cloned().fold( v1_rt::rc_empty_map::>(), |acc: Rc>>, item: Rc| { - let item_ident = intern( - intern_table.clone(), - authored_name_at(source_indices.clone(), item.clone()), - ) - .id - .clone(); - let has_structure = (item.connective.clone() != Connective::NoConnective); - if has_structure.clone() { - { - let type_node = Rc::new(Node { - name: item.name.clone(), - span: item.span.clone(), - ident_span: item.ident_span.clone(), - children: item.children.clone(), - connective: item.connective.clone(), - params: Rc::new(vec![]), - inferred: None, - return_cardinality: item.return_cardinality.clone(), - uses: Rc::new(vec![]), - body: None, - transport: None, - properties: Rc::new(vec![]), - type_annotation: None, - is_self_recursive: false, - has_non_tail_self_call: false, - match_pattern: None, - expr_data: Rc::new(ExprData::NoExprData), - ident: None, - }); - v1_rt::rc_map_insert( - acc.clone(), - item_ident.clone(), - Rc::new(TypeBinding { - name: authored_name_at(source_indices.clone(), item.clone()), - resolved: type_node.clone(), - provenance: Rc::new(SubValueRelation::SubValueUnknown), - }), - ) - } + if is_namespace_alias_item(item.clone(), source_indices.clone()) { + acc.clone() } else { - if (((item.inferred.clone() != None) - && ((item.params.clone().len() as i64) == 0)) - && (item.body.clone() == None)) { - { - let alias_node = Rc::new(Node { - name: item.name.clone(), - span: item.span.clone(), - ident_span: item.ident_span.clone(), - children: Rc::new(vec![]), - connective: Connective::NoConnective, - params: Rc::new(vec![]), - inferred: item.inferred.clone(), - return_cardinality: item.return_cardinality.clone(), - uses: Rc::new(vec![]), - body: None, - transport: None, - properties: Rc::new(vec![]), - type_annotation: None, - is_self_recursive: false, - has_non_tail_self_call: false, - match_pattern: None, - expr_data: Rc::new(ExprData::NoExprData), - ident: None, - }); - v1_rt::rc_map_insert( - acc.clone(), - item_ident.clone(), - Rc::new(TypeBinding { - name: authored_name_at(source_indices.clone(), item.clone()), - resolved: alias_node.clone(), - provenance: Rc::new(SubValueRelation::SubValueUnknown), - }), - ) - } - } else { - if ((item.transport.clone() == None) - && ((item.children.clone().len() as i64) > 0)) - { + let item_ident = intern( + intern_table.clone(), + authored_name_at(source_indices.clone(), item.clone()), + ) + .id + .clone(); + let has_structure = (item.connective.clone() != Connective::NoConnective); + if has_structure.clone() { { - let ref_node = nominal_ref_node( - authored_name_at(source_indices.clone(), item.clone()), - item.span.clone(), - item.ident_span.clone(), - ); + let type_node = Rc::new(Node { + name: item.name.clone(), + span: item.span.clone(), + ident_span: item.ident_span.clone(), + children: item.children.clone(), + connective: item.connective.clone(), + params: Rc::new(vec![]), + inferred: None, + return_cardinality: item.return_cardinality.clone(), + uses: Rc::new(vec![]), + body: None, + transport: None, + properties: Rc::new(vec![]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + }); v1_rt::rc_map_insert( acc.clone(), item_ident.clone(), @@ -15353,28 +15420,94 @@ pub fn build_type_env_unresolved( source_indices.clone(), item.clone(), ), - resolved: ref_node.clone(), + resolved: type_node.clone(), provenance: Rc::new(SubValueRelation::SubValueUnknown), }), ) } } else { - if ((((((item.properties.clone().len() as i64) > 0) - && (item.connective.clone() == Connective::NoConnective)) - && (item.transport.clone() == None)) - && (item.inferred.clone() == None)) + if (((item.inferred.clone() != None) && ((item.params.clone().len() as i64) == 0)) + && (item.body.clone() == None)) { - v1_rt::rc_map_insert( - acc.clone(), - item_ident.clone(), - nominal_type_binding(authored_name_at( - source_indices.clone(), - item.clone(), - )), - ) + { + let alias_node = Rc::new(Node { + name: item.name.clone(), + span: item.span.clone(), + ident_span: item.ident_span.clone(), + children: Rc::new(vec![]), + connective: Connective::NoConnective, + params: Rc::new(vec![]), + inferred: item.inferred.clone(), + return_cardinality: item.return_cardinality.clone(), + uses: Rc::new(vec![]), + body: None, + transport: None, + properties: Rc::new(vec![]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + }); + v1_rt::rc_map_insert( + acc.clone(), + item_ident.clone(), + Rc::new(TypeBinding { + name: authored_name_at( + source_indices.clone(), + item.clone(), + ), + resolved: alias_node.clone(), + provenance: Rc::new(SubValueRelation::SubValueUnknown), + }), + ) + } } else { - acc.clone() + if ((item.transport.clone() == None) + && ((item.children.clone().len() as i64) > 0)) + { + { + let ref_node = nominal_ref_node( + authored_name_at(source_indices.clone(), item.clone()), + item.span.clone(), + item.ident_span.clone(), + ); + v1_rt::rc_map_insert( + acc.clone(), + item_ident.clone(), + Rc::new(TypeBinding { + name: authored_name_at( + source_indices.clone(), + item.clone(), + ), + resolved: ref_node.clone(), + provenance: Rc::new( + SubValueRelation::SubValueUnknown, + ), + }), + ) + } + } else { + if ((((((item.properties.clone().len() as i64) > 0) + && (item.connective.clone() == Connective::NoConnective)) + && (item.transport.clone() == None)) + && (item.inferred.clone() == None)) + && ((item.params.clone().len() as i64) == 0)) + { + v1_rt::rc_map_insert( + acc.clone(), + item_ident.clone(), + nominal_type_binding(authored_name_at( + source_indices.clone(), + item.clone(), + )), + ) + } else { + acc.clone() + } + } } } } diff --git a/src/v1/stage0/src/v1_compiler_parse.rs b/src/v1/stage0/src/v1_compiler_parse.rs index cab45623a09..3ba52038faf 100644 --- a/src/v1/stage0/src/v1_compiler_parse.rs +++ b/src/v1/stage0/src/v1_compiler_parse.rs @@ -2517,7 +2517,7 @@ pub fn parse_item(tokens: Rc, ctx: Rc) -> Rc { parse_data_after_kw(tokens.clone(), ctx.clone(), start_span.clone()) } + BodyKind::AliasBody => { + parse_alias_after_kw(tokens.clone(), ctx.clone(), start_span.clone()) + } BodyKind::NoBody => { let prefix = parse_item_prefix(tokens.clone(), ctx.clone(), form.clone()); if has_err(prefix.err.clone()) { @@ -9510,6 +9513,126 @@ pub fn parse_data_def(tokens: Rc, ctx: Rc) -> Rc, + ctx: Rc, + start_span: Rc, +) -> Rc { + { + let dummy = Rc::new(Node { + name: "".to_string(), + span: start_span.clone(), + ident_span: None, + children: Rc::new(vec![]), + params: Rc::new(vec![]), + inferred: None, + return_cardinality: Cardinality::Required, + uses: Rc::new(vec![]), + body: None, + connective: Connective::NoConnective, + transport: None, + properties: Rc::new(vec![]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + }); + let r = expect_ident(tokens.clone()); + if has_err(r.err.clone()) { + return Rc::new(ItemResult { + item: dummy.clone(), + tokens: r.tokens.clone(), + ctx: ctx.clone(), + err: r.err.clone(), + }); + } + let name = r.name.clone(); + let name_span = r.span.clone(); + let named_dummy = Rc::new(Node { + name: name.clone(), + span: start_span.clone(), + ident_span: Some(name_span.clone()), + children: Rc::new(vec![]), + params: Rc::new(vec![]), + inferred: None, + return_cardinality: Cardinality::Required, + uses: Rc::new(vec![]), + body: None, + connective: Connective::NoConnective, + transport: None, + properties: Rc::new(vec![]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + }); + let r = expect(r.tokens.clone(), Rc::new(ExpectedToken::ExpectEq)); + if has_err(r.err.clone()) { + return Rc::new(ItemResult { + item: named_dummy.clone(), + tokens: r.tokens.clone(), + ctx: ctx.clone(), + err: r.err.clone(), + }); + } + let r = parse_dotted_ident(r.tokens.clone()); + if has_err(r.err.clone()) { + return Rc::new(ItemResult { + item: named_dummy.clone(), + tokens: r.tokens.clone(), + ctx: ctx.clone(), + err: r.err.clone(), + }); + } + let target_path = r.name.clone(); + let target_prop = make_field_init_node( + "namespace_alias_target".to_string(), + make_expr_node( + Rc::new(ExprData::ExprLiteral { + value: Rc::new(LiteralValue::LitStr { + value: target_path.clone(), + }), + }), + Rc::new(vec![]), + None, + r.span.clone(), + ), + start_span.clone(), + no_span(), + ); + let item = Rc::new(Node { + name: name.clone(), + span: start_span.clone(), + ident_span: Some(name_span.clone()), + children: Rc::new(vec![]), + params: Rc::new(vec![]), + inferred: None, + return_cardinality: Cardinality::Required, + uses: Rc::new(vec![]), + body: None, + connective: Connective::NoConnective, + transport: None, + properties: Rc::new(vec![target_prop.clone()]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + }); + Rc::new(ItemResult { + item: item.clone(), + tokens: skip_newlines(r.tokens.clone()), + ctx: ctx.clone(), + err: None, + }) + } +} + pub fn parse_data_after_kw( tokens: Rc, ctx: Rc, diff --git a/src/v1/tests/src/lib.rs b/src/v1/tests/src/lib.rs index d8088c93c0d..4727a428e0f 100644 --- a/src/v1/tests/src/lib.rs +++ b/src/v1/tests/src/lib.rs @@ -104,6 +104,7 @@ mod measure_periphery_emit_test; mod measure_value_arg_unit_collapse_test; #[cfg(test)] mod module_authority_resolution_test; +mod namespace_alias_decl_test; #[cfg(test)] mod nested_fold_generic_param_emit_test; mod nested_list_alias_emit_test; diff --git a/src/v1/tests/src/namespace_alias_decl_test.rs b/src/v1/tests/src/namespace_alias_decl_test.rs new file mode 100644 index 00000000000..642fb966fdd --- /dev/null +++ b/src/v1/tests/src/namespace_alias_decl_test.rs @@ -0,0 +1,57 @@ +//! §13 namespace alias-decl parse + typecheck-env binding witnesses. +//! +//! GREEN: `alias Binding = qualified.path` parses and binds without importing the +//! target module directly — bare references resolve through the alias. +//! RED: a dangling alias target is fail-closed (no fabricated binding). + +use crate::helpers::{compile_multi_target, diagnostic_messages}; +use v1_compiler::v1_compiler_compile::RenderTarget; +use v1_compiler::v1_compiler_infer::is_error_diagnostic; + +const TARGET_LIB: &str = "module alias_fixture.target\n\ + type Carrier { x: Int }\n"; + +const GREEN_CONSUMER: &str = "module alias_fixture.consumer\n\ + alias CarrierAlias = alias_fixture.target.Carrier\n\ + fn echo(c: CarrierAlias) -> CarrierAlias { c }\n"; + +const DANGLING_ALIAS: &str = "module alias_fixture.dangling\n\ + alias MissingAlias = alias_fixture.nowhere.Missing\n\ + fn noop() -> Int { 0 }\n"; + +fn error_messages(result: &v1_compiler::v1_compiler_compile::PipelineResult) -> Vec { + result + .diagnostics + .iter() + .filter(|d| is_error_diagnostic(d.diagnostic.clone())) + .map(|d| format!("{:?}", d.diagnostic)) + .collect() +} + +#[test] +fn namespace_alias_resolves_without_direct_import() { + let result = compile_multi_target( + &[("target.dag", TARGET_LIB), ("consumer.dag", GREEN_CONSUMER)], + RenderTarget::Dag, + ); + let errors = error_messages(&result); + assert!( + errors.is_empty(), + "alias to a type in a module not imported directly must typecheck; errors:\n{}\nall:\n{}", + errors.join("\n"), + diagnostic_messages(&result).join("\n") + ); +} + +#[test] +fn namespace_alias_dangling_target_refuses() { + let result = compile_multi_target( + &[("target.dag", TARGET_LIB), ("dangling.dag", DANGLING_ALIAS)], + RenderTarget::Dag, + ); + let errors = error_messages(&result); + assert!( + !errors.is_empty(), + "dangling alias target must refuse (fail-closed), got clean compile" + ); +} diff --git a/src/v2/lens/test_migration_debt.dag b/src/v2/lens/test_migration_debt.dag index 54870c3b85a..4d6d46730a0 100644 --- a/src/v2/lens/test_migration_debt.dag +++ b/src/v2/lens/test_migration_debt.dag @@ -6,7 +6,7 @@ import v2.std.collection { List } import v2.std.logic { Bool } import v2.std.text { String } -data test_migration_debt_module_count_baseline: Int = 80 +data test_migration_debt_module_count_baseline: Int = 81 data test_migration_debt_total_loc_baseline: Int = 28054 data test_migration_debt_total_test_fns_baseline: Int = 881