New type analysis WIP.

This commit is contained in:
Jesse Brault 2026-09-04 21:14:12 -05:00
parent d07135b3c6
commit 21fa082b44
11 changed files with 267 additions and 99 deletions

View File

@ -10,7 +10,7 @@ pub fn get_name_for_type<'ctx>(type_info: &TypeInfo, ctx: &'ctx AnalysisContext)
TypeInfo::Constructor(_constructor_type_info) => {
todo!()
}
TypeInfo::TypeConstructor(type_constructor_info) => {
TypeInfo::Class(type_constructor_info) => {
let class_symbol = &ctx.symbols()[type_constructor_info.class_symbol_id()];
class_symbol.declared_name()
}

View File

@ -6,12 +6,13 @@ use crate::diagnostic_factories::symbol_not_found;
use crate::semantic_analysis::diagnostic_helpers::symbol_already_declared;
use crate::semantic_analysis::scope::{Scope, ScopeId};
use crate::semantic_analysis::symbol::{Symbol, SymbolId};
use crate::semantic_analysis::type_info::{TypeInfo, TypeInfoId};
use crate::semantic_analysis::type_info::{ClassTypeInfo, TypeInfo, TypeInfoId};
use crate::source_range::SourceRange;
use std::collections::HashMap;
use std::rc::Rc;
pub struct AnalysisContext {
#[derive(Debug, Clone)]
struct AnalysisState {
fqn_stack: Vec<Rc<str>>,
scopes: Vec<Scope>,
current_scope_id: Option<ScopeId>,
@ -23,8 +24,8 @@ pub struct AnalysisContext {
nodes_to_type_infos: HashMap<NodeId, TypeInfoId>,
}
impl AnalysisContext {
pub fn new() -> Self {
impl Default for AnalysisState {
fn default() -> Self {
Self {
fqn_stack: Vec::new(),
scopes: Vec::new(),
@ -37,101 +38,129 @@ impl AnalysisContext {
nodes_to_type_infos: HashMap::new(),
}
}
}
pub struct AnalysisContext {
state: Box<AnalysisState>,
previous_state: Option<Box<AnalysisState>>,
}
impl AnalysisContext {
pub fn new() -> Self {
Self {
state: AnalysisState::default().into(),
previous_state: None,
}
}
pub fn commit(&mut self) {
todo!()
self.previous_state = Some(self.state.clone());
}
pub fn rollback(&mut self) {
todo!()
self.state = self.previous_state.take().unwrap_or_default();
}
#[deprecated]
pub fn symbols(&self) -> &[Symbol] {
&self.symbols
&self.state.symbols
}
#[deprecated]
pub fn nodes_to_symbols(&self) -> &HashMap<NodeId, SymbolId> {
&self.nodes_to_symbols
&self.state.nodes_to_symbols
}
#[deprecated]
pub fn type_infos(&self) -> &[TypeInfo] {
&self.type_infos
&self.state.type_infos
}
#[deprecated]
pub fn symbols_to_type_infos(&self) -> &HashMap<SymbolId, TypeInfoId> {
&self.symbols_to_type_infos
&self.state.symbols_to_type_infos
}
#[deprecated]
pub fn nodes_to_type_infos(&self) -> &HashMap<NodeId, TypeInfoId> {
&self.nodes_to_type_infos
&self.state.nodes_to_type_infos
}
pub fn push_fqn_part(&mut self, part: Rc<str>) {
self.fqn_stack.push(part);
self.state.fqn_stack.push(part);
}
pub fn pop_fqn_part(&mut self) {
self.fqn_stack.pop();
self.state.fqn_stack.pop();
}
pub fn resolve_fqn(&self, suffix: &str) -> String {
let mut fqn = self.fqn_stack.clone();
let mut fqn = self.state.fqn_stack.clone();
fqn.push(suffix.into());
fqn.join("::")
}
pub fn push_scope(&mut self, _debug_name: &str) -> ScopeId {
let scope = Scope::new(self.current_scope_id);
self.scopes.push(scope);
self.current_scope_id = Some(self.scopes.len() - 1);
self.current_scope_id.unwrap()
}
fn get_scope(&self, scope_id: ScopeId) -> &Scope {
self.scopes.get(scope_id).expect(&format!(
self.state.scopes.get(scope_id).expect(&format!(
"scope_id {} is not a valid index of self.scopes",
scope_id
))
}
fn get_scope_mut(&mut self, scope_id: ScopeId) -> &mut Scope {
self.scopes.get_mut(scope_id).expect(&format!(
self.state.scopes.get_mut(scope_id).expect(&format!(
"scope_id {} is not a valid index of self.scopes",
scope_id
))
}
fn get_current_scope(&self) -> &Scope {
self.get_scope(self.current_scope_id.expect("current_scope_id is None"))
}
fn get_current_scope_mut(&mut self) -> &mut Scope {
self.get_scope_mut(self.current_scope_id.expect("current_scope_id is None"))
/// Pushes a new `Scope` on top of the scope stack, returning the `ScopeId` for the newly pushed
/// scope.
pub fn push_scope(&mut self, _debug_name: &str) -> ScopeId {
let scope = Scope::new(self.state.current_scope_id);
self.state.scopes.push(scope);
self.state.current_scope_id = Some(self.state.scopes.len() - 1);
self.state.current_scope_id.unwrap()
}
pub fn pop_scope(&mut self) {
self.current_scope_id = self.get_current_scope().parent_id();
self.state.current_scope_id = self
.state
.current_scope_id
.and_then(|current_scope_id| self.state.scopes.get(current_scope_id))
.and_then(|current_scope| current_scope.parent_id())
}
/// Designates the given `node_id` as belonging to the current scope.
pub fn associate_node_to_current_scope(&mut self, node_id: NodeId) {
self.nodes_to_scopes.insert(
self.state.nodes_to_scopes.insert(
node_id,
self.current_scope_id.expect("current_scope_id is None"),
self.state
.current_scope_id
.expect("current_scope_id is None"),
);
}
/// Inserts the given symbol into the Scope corresponding to the given ScopeId. **This is a low
/// level operation and alternate methods should be preferred.**
/// Inserts the given symbol into the Scope corresponding to the given ScopeId.
///
/// Danger: If a symbol already exists in the corresponding Scope with the same declared name,
/// it will be overwritten, leading to dangling symbols/symbol ids.
/// ## Panics
/// - If the scope identified by `scope_id` already contains a symbol with the `declared_name`
/// obtained from the given `Symbol`.
fn insert_symbol_in_scope(&mut self, scope_id: ScopeId, symbol: Symbol) -> SymbolId {
// get declared name
let declared_name = symbol.declared_name_owned();
if self.get_scope(scope_id).has_symbol(symbol.declared_name()) {
panic!(
"Symbol with declared_name {} already exists in scope_id {}",
symbol.declared_name(),
scope_id
);
}
// push the symbol
self.symbols.push(symbol);
let symbol_id = self.symbols.len() - 1;
self.state.symbols.push(symbol);
let symbol_id = self.state.symbols.len() - 1;
// put it in scope
self.get_scope_mut(scope_id)
@ -140,28 +169,46 @@ impl AnalysisContext {
symbol_id
}
/// Sets the symbol identified by `symbol_id` for the node identified by `node_id`.
pub fn associate_node_to_symbol(&mut self, node_id: NodeId, symbol_id: SymbolId) {
self.nodes_to_symbols.insert(node_id, symbol_id);
self.state.nodes_to_symbols.insert(node_id, symbol_id);
}
fn get_symbol_in_scope(&self, scope: &Scope, declared_name: &str) -> Option<&Symbol> {
/// Finds a symbol with a matching name to `declared_name` in the provided `Scope`. Returns an
/// `Option` maybe containing a reference to that `Symbol`.
///
/// ## Panics
/// - If the `symbol_id` for the matching `Symbol` is not a valid index of `self.state.symbols`.
fn find_symbol_in_scope(&self, scope: &Scope, declared_name: &str) -> Option<&Symbol> {
scope.get_symbol_id(declared_name).map(|symbol_id| {
self.symbols.get(symbol_id).expect(&format!(
self.state.symbols.get(symbol_id).expect(&format!(
"symbol_id {} is not a valid index of self.symbols",
symbol_id
))
})
}
/// Use this function only when there is no node associated with the symbol. Otherwise use
/// `try_insert_symbol_in_node_scope`.
/// Inserts the given `Symbol` into the scope identified by `scope_id`.
///
/// ## Examples
/// ```rust
/// use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
/// use dmc_lib::semantic_analysis::symbol::{Symbol, VariableSymbol};
///
/// let mut analysis_context = AnalysisContext::new();
/// let scope_id = analysis_context.push_scope("some scope");
/// let symbol = Symbol::Variable(VariableSymbol::new("my_variable".into(), None, false));
/// let result = analysis_context.try_insert_symbol_in_scope(symbol, scope_id);
/// assert!(matches!(result, Ok(_)));
/// ```
pub fn try_insert_symbol_in_scope(
&mut self,
to_insert: Symbol,
scope_id: ScopeId,
) -> Result<SymbolId, Diagnostic> {
let scope = self.get_scope(scope_id);
if let Some(already_declared) = self.get_symbol_in_scope(scope, to_insert.declared_name()) {
if let Some(already_declared) = self.find_symbol_in_scope(scope, to_insert.declared_name())
{
Err(symbol_already_declared(already_declared, &to_insert))
} else {
let symbol_id = self.insert_symbol_in_scope(scope_id, to_insert);
@ -170,18 +217,39 @@ impl AnalysisContext {
}
}
/// Inserts the given symbol into the scope belonging to the given node_id, and sets the node's
/// associated symbol id to the resultant symbol id. Returns `Ok(SymbolId)` if the insert was
/// successful, else `Err(Diagnostic)`.
///
/// ## Examples
/// ```rust
/// use dmc_lib::semantic_analysis::analysis_context::AnalysisContext;
/// use dmc_lib::semantic_analysis::symbol::{Symbol, VariableSymbol};
///
/// let mut analysis_context = AnalysisContext::new();
/// analysis_context.push_scope("some scope");
/// let node_id = 0;
/// analysis_context.associate_node_to_current_scope(node_id);
/// let symbol = Symbol::Variable(VariableSymbol::new("my_variable".into(), None, false));
/// let result = analysis_context.try_insert_associate_symbol_in_node_scope(symbol, node_id);
/// assert!(matches!(result, Ok(_)));
/// ```
pub fn try_insert_associate_symbol_in_node_scope(
&mut self,
to_insert: Symbol,
owner_node_id: NodeId,
) -> Result<SymbolId, Diagnostic> {
let node_scope_id = self.nodes_to_scopes.get(&owner_node_id).expect(&format!(
"owner_node_id {} is not in self.nodes_to_scopes",
owner_node_id
));
let node_scope_id = self
.state
.nodes_to_scopes
.get(&owner_node_id)
.expect(&format!(
"owner_node_id {} is not in self.state.nodes_to_scopes",
owner_node_id
));
let node_scope = self.get_scope(*node_scope_id);
if let Some(already_declared) =
self.get_symbol_in_scope(node_scope, to_insert.declared_name())
self.find_symbol_in_scope(node_scope, to_insert.declared_name())
{
Err(symbol_already_declared(already_declared, &to_insert))
} else {
@ -191,12 +259,15 @@ impl AnalysisContext {
}
}
/// Gets the `SymbolId` of the node with the declared name in the containing scope of the node
/// with the given `NodeId`.
fn get_symbol_id_by_declared_name_in_node_scope(
&self,
node_id: NodeId,
declared_name: &str,
) -> Option<SymbolId> {
let scope_id = self
.state
.nodes_to_scopes
.get(&node_id)
.expect(&format!("node_id {} has no associated scope", node_id));
@ -204,6 +275,8 @@ impl AnalysisContext {
scope.get_symbol_id(declared_name)
}
/// Finds the symbol for the node with the given node id and declared name and sets the node's
/// symbol to that result.
pub fn associate_node_with_self_symbol(&mut self, node_id: NodeId, declared_name: &str) {
let symbol_id = self
.get_symbol_id_by_declared_name_in_node_scope(node_id, declared_name)
@ -221,6 +294,7 @@ impl AnalysisContext {
node_source_range: &SourceRange,
) -> Result<(), Diagnostic> {
let scope_id = self
.state
.nodes_to_scopes
.get(&node_id)
.expect(&format!("node_id {} has no associated scope", node_id));
@ -250,37 +324,43 @@ impl AnalysisContext {
}
}
#[deprecated]
pub fn insert_type_info(&mut self, type_info: TypeInfo) -> TypeInfoId {
self.type_infos.push(type_info);
self.type_infos.len() - 1
self.state.type_infos.push(type_info);
self.state.type_infos.len() - 1
}
#[deprecated]
pub fn insert_type_info_for_node(
&mut self,
type_info: TypeInfo,
node_id: NodeId,
) -> TypeInfoId {
self.type_infos.push(type_info);
let type_info_id = self.type_infos.len() - 1;
self.nodes_to_type_infos.insert(node_id, type_info_id);
self.state.type_infos.push(type_info);
let type_info_id = self.state.type_infos.len() - 1;
self.state.nodes_to_type_infos.insert(node_id, type_info_id);
type_info_id
}
pub fn associate_symbol_to_type(&mut self, symbol_id: SymbolId, type_info_id: TypeInfoId) {
self.symbols_to_type_infos.insert(symbol_id, type_info_id);
self.state
.symbols_to_type_infos
.insert(symbol_id, type_info_id);
}
pub fn associate_node_and_symbol_to_type(&mut self, node_id: NodeId, type_info_id: TypeInfoId) {
let symbol_id = self
.state
.nodes_to_symbols
.get(&node_id)
.expect(&format!("node_id {} has no associated symbol", node_id));
self.associate_symbol_to_type(*symbol_id, type_info_id);
self.nodes_to_type_infos.insert(node_id, type_info_id);
self.state.nodes_to_type_infos.insert(node_id, type_info_id);
}
pub fn get_type_info_id_for_node(&self, node_id: NodeId) -> TypeInfoId {
*self
.state
.nodes_to_type_infos
.get(&node_id)
.expect(&format!("node_id {} has no associated type", node_id))
@ -288,37 +368,44 @@ impl AnalysisContext {
pub fn get_type_info_for_node(&self, node_id: NodeId) -> &TypeInfo {
let type_info_id = self.get_type_info_id_for_node(node_id);
self.type_infos
self.state
.type_infos
.get(type_info_id)
.expect(&format!("invalid type_info_id {}", type_info_id))
}
pub fn get_type_info_by_id(&self, type_info_id: TypeInfoId) -> &TypeInfo {
self.type_infos
self.state
.type_infos
.get(type_info_id)
.expect(&format!("invalid type_info_id {}", type_info_id))
}
pub fn associate_node_to_type(&mut self, node_id: NodeId, type_info_id: TypeInfoId) {
self.nodes_to_type_infos.insert(node_id, type_info_id);
self.state.nodes_to_type_infos.insert(node_id, type_info_id);
}
pub fn lookup_type_for_node_via_symbol(&self, node_id: NodeId) -> TypeInfoId {
let symbol_id = self
.state
.nodes_to_symbols
.get(&node_id)
.expect(&format!("node_id {} has no associated symbol", node_id));
let symbol_type_info_id = self.symbols_to_type_infos.get(symbol_id).expect(&format!(
"symbol_id {} has no associated type_info",
symbol_id
));
let symbol_type_info_id = self
.state
.symbols_to_type_infos
.get(symbol_id)
.expect(&format!(
"symbol_id {} has no associated type_info",
symbol_id
));
*symbol_type_info_id
}
pub fn find_symbol_by_fqn(&self, fqn: &str) -> Option<SymbolId> {
// This is quite naive and probably very slow; we will certainly use trees of HashMaps (or
// structs with a HashMap and children) to represent the fqn hierarchy.
for (id, symbol) in self.symbols.iter().enumerate() {
for (id, symbol) in self.state.symbols.iter().enumerate() {
match symbol {
Symbol::Class(class_symbol) => {
if class_symbol.fqn() == fqn {
@ -335,4 +422,43 @@ impl AnalysisContext {
}
None
}
pub fn get_symbol_id(&self, node_id: NodeId) -> Option<SymbolId> {
self.state.nodes_to_scopes.get(&node_id).cloned()
}
pub fn make_class_type(
&mut self,
class_symbol_id: SymbolId,
constructor_symbol_id: Option<SymbolId>,
) -> TypeInfoId {
if let Some(type_info_id) = self.state.symbols_to_type_infos.get(&class_symbol_id) {
*type_info_id
} else {
let type_info =
TypeInfo::Class(ClassTypeInfo::new(class_symbol_id, constructor_symbol_id));
self.state.type_infos.push(type_info);
let type_info_id = self.state.type_infos.len() - 1;
self.state
.symbols_to_type_infos
.insert(class_symbol_id, type_info_id);
type_info_id
}
}
pub fn resolve_type_info_id(&mut self, node_id: NodeId, declared_name: &str) -> TypeInfoId {
todo!()
}
pub fn int_type(&mut self) -> &TypeInfoId {
todo!()
}
pub fn double_type(&mut self) -> &TypeInfoId {
todo!()
}
pub fn type_by_fqn(&mut self, fqn: &str) -> &TypeInfoId {
todo!()
}
}

View File

@ -7,8 +7,7 @@ use crate::ast::parameter::Parameter;
use crate::semantic_analysis::analysis_context::AnalysisContext;
use crate::semantic_analysis::symbol::SymbolId;
use crate::semantic_analysis::type_info::{
ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeConstructorInfo, TypeInfo,
TypeInfoId,
ClassTypeInfo, ConstructorTypeInfo, FunctionTypeInfo, InstanceTypeInfo, TypeInfo, TypeInfoId,
};
pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) {
@ -148,7 +147,7 @@ fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) {
// todo: fields, methods
// Self type constructor
let type_constructor_type_info = TypeInfo::TypeConstructor(TypeConstructorInfo::new(
let type_constructor_type_info = TypeInfo::Class(ClassTypeInfo::new(
ctx.nodes_to_symbols()[&class.node_id()],
constructor_type_info_id,
));

View File

@ -255,7 +255,7 @@ fn resolve_types_call(call: &Call, ctx: &mut AnalysisContext, diagnostics: &mut
let callee_type_info = ctx.get_type_info_for_node(call.callee().node_id());
match callee_type_info {
TypeInfo::TypeConstructor(type_constructor_info) => {
TypeInfo::Class(type_constructor_info) => {
let class_symbol =
ctx.symbols()[type_constructor_info.class_symbol_id()].unwrap_class_symbol();
match class_symbol.constructor_symbol_id() {

View File

@ -150,7 +150,7 @@ pub fn can_assign_right_to_left(left: &TypeInfo, right: &TypeInfo, ctx: &Analysi
TypeInfo::Constructor(_) => {
panic!()
}
TypeInfo::TypeConstructor(_) => {
TypeInfo::Class(_) => {
panic!()
}
TypeInfo::Instance(left_instance_type_info) => match right {

View File

@ -4,6 +4,7 @@ use std::rc::Rc;
pub type ScopeId = usize;
#[derive(Debug, Clone)]
pub struct Scope {
parent_id: Option<ScopeId>,
symbols: HashMap<Rc<str>, SymbolId>,
@ -21,6 +22,10 @@ impl Scope {
self.parent_id
}
pub fn has_symbol(&self, declared_name: &str) -> bool {
self.symbols.contains_key(declared_name)
}
pub fn insert_symbol(&mut self, declared_name: Rc<str>, symbol_id: SymbolId) {
self.symbols.insert(declared_name, symbol_id);
}

View File

@ -5,7 +5,7 @@ use std::rc::Rc;
pub type SymbolId = usize;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Symbol {
Class(ClassSymbol),
Field(FieldSymbol),
@ -60,7 +60,7 @@ impl Symbol {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ClassSymbol {
declared_name: Rc<str>,
source_range: Option<SourceRange>,
@ -129,7 +129,7 @@ impl ClassSymbol {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct FieldSymbol {
declared_name: Rc<str>,
declared_name_source_range: Option<SourceRange>,
@ -156,7 +156,7 @@ impl FieldSymbol {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum FunctionType {
Function,
Constructor,
@ -164,7 +164,7 @@ pub enum FunctionType {
StaticMethod,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct FunctionSymbol {
declared_name: Rc<str>,
declared_name_source_range: Option<SourceRange>,
@ -219,7 +219,7 @@ impl FunctionSymbol {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ParameterSymbol {
name: Rc<str>,
source_range: Option<SourceRange>,
@ -243,7 +243,7 @@ impl ParameterSymbol {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct VariableSymbol {
name: Rc<str>,
source_range: Option<SourceRange>,

View File

@ -10,16 +10,14 @@ pub fn collect_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisConte
}
fn collect_types_class(class: &Class, ctx: &mut AnalysisContext) {
let class_symbol_id = *ctx
.nodes_to_symbols()
.get(&class.node_id())
.expect(&format!(
"Could not find class symbol for {} {}",
class.node_id(),
class.declared_name()
));
let maybe_constructor_type_info_id = class
.constructor()
.and_then(|constructor| ctx.get_symbol_id(constructor.node_id()));
let self_instance_type_info = TypeInfo::Instance(InstanceTypeInfo::new(class_symbol_id));
let self_instance_type_info_id = ctx.insert_type_info(self_instance_type_info);
ctx.associate_symbol_to_type(class_symbol_id, self_instance_type_info_id)
let class_symbol_id = ctx.get_symbol_id(class.node_id()).expect(&format!(
"Could not find symbol for {} {}",
class.node_id(),
class.declared_name()
));
ctx.make_class_type(class_symbol_id, maybe_constructor_type_info_id);
}

View File

@ -1,3 +1,13 @@
use crate::ast::compilation_unit::CompilationUnit;
use crate::semantic_analysis::analysis_context::AnalysisContext;
use crate::semantic_analysis::type_analysis::collect::collect_types;
use crate::semantic_analysis::type_analysis::resolve::resolve_types;
mod collect;
mod infer;
mod resolve;
pub fn analyze_types(compilation_unit: &CompilationUnit, analysis_context: &mut AnalysisContext) {
collect_types(compilation_unit, analysis_context);
resolve_types(compilation_unit, analysis_context);
}

View File

@ -1 +1,31 @@
use crate::ast::compilation_unit::CompilationUnit;
use crate::ast::function::Function;
use crate::ast::parameter::Parameter;
use crate::ast::type_use::TypeUse;
use crate::semantic_analysis::analysis_context::AnalysisContext;
pub fn resolve_types(compilation_unit: &CompilationUnit, ctx: &mut AnalysisContext) {
for function in compilation_unit.functions() {
resolve_types_function(function, ctx);
}
for extern_function in compilation_unit.extern_functions() {}
for class in compilation_unit.classes() {}
}
fn resolve_types_function(function: &Function, ctx: &mut AnalysisContext) {
for parameter in function.parameters() {
resolve_types_parameter(parameter, ctx);
}
if let Some(return_type) = function.return_type() {
resolve_types_type_use(return_type, ctx);
}
}
fn resolve_types_parameter(parameter: &Parameter, ctx: &mut AnalysisContext) {
resolve_types_type_use(parameter.type_use(), ctx);
}
fn resolve_types_type_use(type_use: &TypeUse, ctx: &mut AnalysisContext) {
let type_info_id = ctx.resolve_type_info_id(type_use.node_id(), type_use.declared_name());
todo!()
}

View File

@ -6,9 +6,9 @@ pub type TypeInfoId = usize;
#[derive(Clone, Debug)]
pub enum TypeInfo {
Any,
Function(FunctionTypeInfo),
Class(ClassTypeInfo),
Constructor(ConstructorTypeInfo),
TypeConstructor(TypeConstructorInfo),
Function(FunctionTypeInfo),
Instance(InstanceTypeInfo),
Int,
Double,
@ -24,9 +24,9 @@ impl TypeInfo {
}
}
pub fn unwrap_type_constructor(&self) -> &TypeConstructorInfo {
pub fn unwrap_class(&self) -> &ClassTypeInfo {
match self {
TypeInfo::TypeConstructor(type_constructor_info) => type_constructor_info,
TypeInfo::Class(type_constructor_info) => type_constructor_info,
_ => panic!("Attempt to unwrap {:?} as TypeConstructor", self),
}
}
@ -89,16 +89,16 @@ impl ConstructorTypeInfo {
}
#[derive(Clone, Debug)]
pub struct TypeConstructorInfo {
pub struct ClassTypeInfo {
class_symbol_id: SymbolId,
constructor_type_info_id: Option<TypeInfoId>,
constructor_symbol_id: Option<SymbolId>,
}
impl TypeConstructorInfo {
pub fn new(class_symbol_id: SymbolId, constructor_type_info_id: Option<TypeInfoId>) -> Self {
impl ClassTypeInfo {
pub fn new(class_symbol_id: SymbolId, constructor_symbol_id: Option<SymbolId>) -> Self {
Self {
class_symbol_id,
constructor_type_info_id,
constructor_symbol_id,
}
}
@ -106,8 +106,8 @@ impl TypeConstructorInfo {
self.class_symbol_id
}
pub fn constructor_type_info_id(&self) -> Option<TypeInfoId> {
self.constructor_type_info_id
pub fn constructor_type_info_id(&self) -> Option<SymbolId> {
self.constructor_symbol_id
}
}