Skip to content

Commit

Permalink
frontend: Add specialize_for_element()
Browse files Browse the repository at this point in the history
  • Loading branch information
dinfuehr committed Oct 13, 2024
1 parent f164500 commit 4bad5ca
Show file tree
Hide file tree
Showing 18 changed files with 236 additions and 54 deletions.
11 changes: 7 additions & 4 deletions dora-frontend/src/aliasck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,16 +498,19 @@ mod tests {

#[test]
#[ignore]
fn impl_alias_generic() {
fn impl_alias_as_return_type() {
ok("
struct Foo[T]
trait TraitA {
type X[T];
type X;
}
impl TraitA for String {
type X[T] = T;
type X = Int64;
}
fn x() {
let x: Int64 = f[String](\"foo\");
}
fn f[T: TraitA](t: T): T::X[Int64] {
fn f[T: TraitA](t: T): T::X {
0
}
");
Expand Down
4 changes: 3 additions & 1 deletion dora-frontend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ pub use crate::extensiondefck::package_for_type;
pub use parsety::{ParsedTraitType, ParsedType, ParsedTypeAst};
pub use path::{parse_path, PathKind};
pub use program_emitter::emit_program;
pub use specialize::{replace_type, specialize_type, specialize_type_array};
pub use specialize::{
replace_type, specialize_for_element, specialize_type, specialize_type_array,
};

pub(crate) mod access;
mod aliasck;
Expand Down
2 changes: 1 addition & 1 deletion dora-frontend/src/parsety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ fn expand_st(
assert_eq!(trait_id, trait_.id());
ty
} else {
unreachable!()
ty
}
}

Expand Down
93 changes: 65 additions & 28 deletions dora-frontend/src/path.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::collections::HashMap;

use dora_parser::ast;
use dora_parser::{ast, Span};

use crate::access::sym_accessible_from;
use crate::sema::{parent_element_or_self, AliasDefinitionId, Element, Sema, SourceFileId};
use crate::sema::{
parent_element_or_self, AliasDefinitionId, Element, Sema, SourceFileId, TypeParamId,
};
use crate::{ErrorMessage, ModuleSymTable, Name, SymbolKind};

pub enum PathKind {
Expand All @@ -27,7 +29,7 @@ pub fn parse_path(
parse_path_self(sa, file_id, element, allow_self, regular)
}

ast::PathSegmentData::Ident(..) => parse_path_ident(sa, table, file_id, regular),
ast::PathSegmentData::Ident(..) => parse_path_ident(sa, file_id, table, element, regular),

ast::PathSegmentData::Error { .. } => Err(()),
}
Expand Down Expand Up @@ -76,8 +78,9 @@ fn parse_path_self(

fn parse_path_ident(
sa: &Sema,
table: &ModuleSymTable,
file_id: SourceFileId,
table: &ModuleSymTable,
element: &dyn Element,
regular: &ast::TypeRegularType,
) -> Result<PathKind, ()> {
let segments = &regular.path.segments;
Expand All @@ -95,37 +98,50 @@ fn parse_path_ident(
let mut previous_sym = sym.expect("missing symbol");

for (idx, segment) in segments.iter().enumerate().skip(1) {
if !previous_sym.is_module() {
let msg = ErrorMessage::ExpectedPath;
sa.report(file_id, segments[idx - 1].span(), msg);
return Err(());
}
if previous_sym.is_module() {
let name = expect_ident(sa, file_id, segment)?;

let name = expect_ident(sa, file_id, segment)?;

let module_id = previous_sym.to_module().expect("expected module");
let module = sa.module(module_id);
let current_sym = module.table().get(name);
let module_id = previous_sym.to_module().expect("expected module");
let module = sa.module(module_id);
let current_sym = module.table().get(name);

if let Some(current_sym) = current_sym {
if sym_accessible_from(sa, current_sym.clone(), module_id) {
previous_sym = current_sym;
if let Some(current_sym) = current_sym {
if sym_accessible_from(sa, current_sym.clone(), module_id) {
previous_sym = current_sym;
} else {
let module = sa.module(module_id);
let name = node.name.name_as_string.clone();
let msg = ErrorMessage::NotAccessibleInModule(module.name(sa), name);
sa.report(file_id, node.span, msg);
return Err(());
}
} else {
let module = sa.module(module_id);
let name = node.name.name_as_string.clone();
let msg = ErrorMessage::NotAccessibleInModule(module.name(sa), name);
sa.report(file_id, node.span, msg);
let name = sa.interner.str(name).to_string();
let module_name = module.name(sa);
sa.report(
file_id,
segment.span(),
ErrorMessage::UnknownIdentifierInModule(module_name, name),
);
return Err(());
}
} else if let SymbolKind::TypeParam(id) = previous_sym {
let name = expect_ident(sa, file_id, segment)?;

let avaiable = lookup_alias_on_type_param(sa, element, id, name).unwrap_or(Vec::new());

if avaiable.len() == 1 {
previous_sym = SymbolKind::Alias(avaiable[0]);
} else {
unimplemented!()
}
} else {
let module = sa.module(module_id);
let name = sa.interner.str(name).to_string();
let module_name = module.name(sa);
sa.report(
file_id,
segment.span(),
ErrorMessage::UnknownIdentifierInModule(module_name, name),
);
let msg = ErrorMessage::ExpectedPath;
let start = segments[0].span().start();
let end = segments[idx - 1].span().end();
let span = Span::new(start, end);
sa.report(file_id, span, msg);
return Err(());
}
}
Expand Down Expand Up @@ -153,6 +169,27 @@ fn available_aliases<'a>(
}
}

fn lookup_alias_on_type_param<'a>(
sa: &'a Sema,
element: &'a dyn Element,
id: TypeParamId,
name: Name,
) -> Option<Vec<AliasDefinitionId>> {
let type_param_definition = element.type_param_definition().expect("no type params");
let mut results = Vec::with_capacity(2);

for bound in type_param_definition.bounds_for_type_param(id) {
let trait_id = bound.trait_id;
let trait_ = sa.trait_(trait_id);

if let Some(id) = trait_.alias_names().get(&name) {
results.push(*id);
}
}

Some(results)
}

fn expect_ident(sa: &Sema, file_id: SourceFileId, segment: &ast::PathSegment) -> Result<Name, ()> {
match segment.as_ref() {
ast::PathSegmentData::Self_(ref node) => {
Expand Down
8 changes: 6 additions & 2 deletions dora-frontend/src/sema/aliases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use std::sync::Arc;
use id_arena::Id;

use crate::sema::{
Element, ElementId, ImplDefinitionId, ModuleDefinitionId, PackageDefinitionId, SourceFileId,
TraitDefinitionId, TypeParamDefinition, Visibility,
Element, ElementId, ImplDefinitionId, ModuleDefinitionId, PackageDefinitionId, Sema,
SourceFileId, TraitDefinitionId, TypeParamDefinition, Visibility,
};
use dora_parser::ast;

Expand Down Expand Up @@ -129,6 +129,10 @@ impl Element for AliasDefinition {
fn to_alias(&self) -> Option<&AliasDefinition> {
Some(self)
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
None
}
}

pub struct AliasBound {
Expand Down
8 changes: 6 additions & 2 deletions dora-frontend/src/sema/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::sema::{
module_path, Element, ElementAccess, ElementId, ExtensionDefinitionId, FctDefinitionId,
ModuleDefinitionId, PackageDefinitionId, Sema, SourceFileId, TypeParamDefinition,
};
use crate::{replace_type, ParsedType, SourceType, SourceTypeArray};
use crate::{specialize_for_element, ParsedType, SourceType, SourceTypeArray};

pub type ClassDefinitionId = Id<ClassDefinition>;

Expand Down Expand Up @@ -202,6 +202,10 @@ impl Element for ClassDefinition {
fn type_param_definition(&self) -> Option<&Rc<TypeParamDefinition>> {
Some(&self.type_param_definition)
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
Some(self.ty())
}
}

impl ElementAccess for ClassDefinition {
Expand Down Expand Up @@ -276,7 +280,7 @@ pub fn find_field_in_class(
if field.name == name {
return Some((
field.id,
replace_type(sa, field.ty(), Some(&type_params), None),
specialize_for_element(sa, field.ty(), cls, &type_params),
));
}
}
Expand Down
4 changes: 4 additions & 0 deletions dora-frontend/src/sema/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ impl Element for ConstDefinition {
fn type_param_definition(&self) -> Option<&Rc<TypeParamDefinition>> {
None
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
None
}
}

#[derive(Clone, Debug, PartialEq)]
Expand Down
17 changes: 11 additions & 6 deletions dora-frontend/src/sema/elements.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use std::rc::Rc;

use crate::sema::{
AliasDefinition, AliasDefinitionId, AliasParent, ClassDefinitionId, ConstDefinitionId,
EnumDefinitionId, ExtensionDefinitionId, FctDefinition, FctDefinitionId, FctParent,
GlobalDefinitionId, ImplDefinition, ImplDefinitionId, ModuleDefinitionId, PackageDefinitionId,
Sema, SourceFileId, StructDefinitionId, TraitDefinition, TraitDefinitionId,
TypeParamDefinition, UseDefinitionId,
use crate::{
sema::{
AliasDefinition, AliasDefinitionId, AliasParent, ClassDefinitionId, ConstDefinitionId,
EnumDefinitionId, ExtensionDefinitionId, FctDefinition, FctDefinitionId, FctParent,
GlobalDefinitionId, ImplDefinition, ImplDefinitionId, ModuleDefinitionId,
PackageDefinitionId, Sema, SourceFileId, StructDefinitionId, TraitDefinition,
TraitDefinitionId, TypeParamDefinition, UseDefinitionId,
},
ty::SourceType,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -58,6 +61,8 @@ pub trait Element {
fn to_alias(&self) -> Option<&AliasDefinition> {
None
}

fn self_ty(&self, sa: &Sema) -> Option<SourceType>;
}

pub trait ElementAccess {
Expand Down
10 changes: 9 additions & 1 deletion dora-frontend/src/sema/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use crate::sema::{
module_path, Element, ElementAccess, ElementId, ExtensionDefinitionId, ModuleDefinitionId,
PackageDefinitionId, Sema, SourceFileId, TypeParamDefinition, Visibility,
};
use crate::ty::SourceTypeArray;
use crate::{SourceType, SourceTypeArray};

use super::new_identity_type_params;

pub type EnumDefinitionId = Id<EnumDefinition>;

Expand Down Expand Up @@ -129,6 +131,12 @@ impl Element for EnumDefinition {
fn type_param_definition(&self) -> Option<&Rc<TypeParamDefinition>> {
Some(&self.type_param_definition)
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
let type_params = self.type_param_definition().type_param_count();
let type_params = new_identity_type_params(type_params);
Some(SourceType::Enum(self.id(), type_params))
}
}

impl ElementAccess for EnumDefinition {
Expand Down
8 changes: 6 additions & 2 deletions dora-frontend/src/sema/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use std::sync::Arc;

use crate::interner::Name;
use crate::sema::{
Element, ElementId, FctDefinitionId, ModuleDefinitionId, PackageDefinitionId, SourceFileId,
TypeParamDefinition,
Element, ElementId, FctDefinitionId, ModuleDefinitionId, PackageDefinitionId, Sema,
SourceFileId, TypeParamDefinition,
};
use crate::ty::SourceType;
use crate::ParsedType;
Expand Down Expand Up @@ -96,4 +96,8 @@ impl Element for ExtensionDefinition {
fn type_param_definition(&self) -> Option<&Rc<TypeParamDefinition>> {
Some(&self.type_param_definition)
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
Some(self.ty())
}
}
10 changes: 10 additions & 0 deletions dora-frontend/src/sema/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,16 @@ impl Element for FctDefinition {
fn to_fct(&self) -> Option<&FctDefinition> {
Some(self)
}

fn self_ty(&self, sa: &Sema) -> Option<SourceType> {
match self.parent {
FctParent::Extension(id) => Some(sa.extension(id).ty()),
FctParent::Impl(id) => Some(sa.impl_(id).extended_ty()),
FctParent::Function => unreachable!(),
FctParent::Trait(..) => unimplemented!(),
FctParent::None => None,
}
}
}

fn path_for_type(sa: &Sema, ty: SourceType) -> String {
Expand Down
4 changes: 4 additions & 0 deletions dora-frontend/src/sema/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,8 @@ impl Element for GlobalDefinition {
fn type_param_definition(&self) -> Option<&Rc<TypeParamDefinition>> {
None
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
None
}
}
6 changes: 5 additions & 1 deletion dora-frontend/src/sema/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use dora_parser::Span;

use crate::sema::{
AliasDefinitionId, Element, ElementId, FctDefinitionId, ModuleDefinitionId,
PackageDefinitionId, SourceFileId, TraitDefinitionId, TypeParamDefinition,
PackageDefinitionId, Sema, SourceFileId, TraitDefinitionId, TypeParamDefinition,
};
use crate::ty::SourceType;
use crate::{ParsedTraitType, ParsedType, TraitType};
Expand Down Expand Up @@ -143,4 +143,8 @@ impl Element for ImplDefinition {
fn to_impl(&self) -> Option<&ImplDefinition> {
Some(self)
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
Some(self.extended_ty())
}
}
4 changes: 4 additions & 0 deletions dora-frontend/src/sema/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ impl Element for StructDefinition {
fn type_param_definition(&self) -> Option<&Rc<TypeParamDefinition>> {
Some(&self.type_param_definition)
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
Some(self.ty())
}
}

impl ElementAccess for StructDefinition {
Expand Down
4 changes: 4 additions & 0 deletions dora-frontend/src/sema/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ impl Element for TraitDefinition {
fn to_trait(&self) -> Option<&TraitDefinition> {
Some(self)
}

fn self_ty(&self, _sa: &Sema) -> Option<SourceType> {
Some(SourceType::This)
}
}

impl ElementAccess for TraitDefinition {
Expand Down
Loading

0 comments on commit 4bad5ca

Please sign in to comment.