Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extern and intrinsics #813

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5e07388
Allow functions to have attributes
Y-Nak Nov 15, 2022
999779d
Add parser for `extern` block
Y-Nak Nov 15, 2022
c9777a1
Remove `;` following trait fn declarations
Y-Nak Nov 15, 2022
fa854e7
Fix `trait`'s `Display` implementation
Y-Nak Nov 15, 2022
04be56d
Allow calling a function defined outside of ingot
Y-Nak Nov 24, 2022
2114017
Add `TypeParam` type to mir types
Y-Nak Nov 26, 2022
623c5d8
Remove monomorphization phase from mir lowering
Y-Nak Nov 26, 2022
e877908
Allow printing function signature with type parameters
Y-Nak Nov 26, 2022
a417df8
Add `emit=mir` option
Y-Nak Nov 26, 2022
921d5cc
Add a missing `self` type in a trait method declaration
Y-Nak Nov 26, 2022
2029ac4
Add query to enumerate all functions in a module
Y-Nak Nov 27, 2022
3a98ace
Add `name` field to `mir::FunctionSig`
Y-Nak Nov 28, 2022
a06037e
Add utility methods to modify mir function body in place
Y-Nak Nov 28, 2022
ee6c237
Enable to lookup a function body by its signature even when its paren…
Y-Nak Nov 28, 2022
6bb4d4d
Define a codegen unit structure
Y-Nak Nov 28, 2022
5fb3bd1
Implement function monomorphization in the CGUs generation phase
Y-Nak Nov 28, 2022
868a0e3
Allow using a generic function which cross the ingot bound
Y-Nak Dec 7, 2022
773add4
Implement CGU lowering
Y-Nak Dec 8, 2022
054aaed
Add runtime functions collection
Y-Nak Dec 10, 2022
8808335
Bump up `indexmap` to `1.9.2`
Y-Nak Dec 10, 2022
05d646d
Add dependency graph resolver for codegen unit
Y-Nak Dec 10, 2022
dc11878
Clean up old yul lower context
Y-Nak Dec 10, 2022
f594b6b
Integrate CGU to the contract compilation and the driver
Y-Nak Dec 12, 2022
872f565
Make clippy satisfy
Y-Nak Dec 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/analyzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ strum = { version = "0.23.0", features = ["derive"] }
semver = "1.0.0"
salsa = "0.16.1"
parking_lot_core = { version = "=0.8.0" } # used by salsa; version pinned for wasm compatibility
indexmap = "1.6.2"
indexmap = "1.9.2"
if_chain = "1.0.1"
smallvec = { version = "1.6.1", features = ["union"] }
petgraph = "0.6.0"
Expand Down
41 changes: 22 additions & 19 deletions crates/analyzer/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ pub trait AnalyzerContext {
fn resolve_name(&self, name: &str, span: Span) -> Result<Option<NamedThing>, IncompleteItem>;
/// Resolves the given path and registers all errors
fn resolve_path(&self, path: &ast::Path, span: Span) -> Result<NamedThing, FatalError>;
/// Resolves the given path only if it is visible. Does not register any errors
/// Resolves the given path only if it is visible. Does not register any
/// errors
fn resolve_visible_path(&self, path: &ast::Path) -> Option<NamedThing>;
/// Resolves the given path. Does not register any errors
fn resolve_any_path(&self, path: &ast::Path) -> Option<NamedThing>;
Expand Down Expand Up @@ -490,53 +491,53 @@ pub enum CallType {
// create, create2 (will be methods of the context struct soon)
BuiltinAssociatedFunction {
contract: ContractId,
function: ContractTypeMethod,
sig: ContractTypeMethod,
},

// MyStruct.foo() (soon MyStruct::foo())
// MyStruct::foo()
AssociatedFunction {
typ: TypeId,
function: FunctionId,
sig: FunctionSigId,
},
// some_struct_or_contract.foo()
ValueMethod {
typ: TypeId,
method: FunctionId,
sig: FunctionSigId,
},
// some_trait.foo()
// The reason this can not use `ValueMethod` is mainly because the trait might not have a
// function implementation and even if it had it might not be the one that ends up getting
// executed. An `impl` block will decide that.
TraitValueMethod {
trait_id: TraitId,
method: FunctionSigId,
sig: FunctionSigId,
// Traits can not directly be used as types but can act as bounds for generics. This is the
// generic type that the method is called on.
generic_type: Generic,
},
External {
contract: ContractId,
function: FunctionId,
sig: FunctionSigId,
},
Pure(FunctionId),
Pure(FunctionSigId),
TypeConstructor(TypeId),
EnumConstructor(EnumVariantId),
}

impl CallType {
pub fn function(&self) -> Option<FunctionId> {
pub fn function_sig(&self) -> Option<FunctionSigId> {
use CallType::*;
match self {
BuiltinFunction(_)
| BuiltinValueMethod { .. }
| TypeConstructor(_)
| EnumConstructor(_)
| Intrinsic(_)
| TraitValueMethod { .. }
| BuiltinAssociatedFunction { .. } => None,
AssociatedFunction { function: id, .. }
| ValueMethod { method: id, .. }
| External { function: id, .. }
AssociatedFunction { sig: id, .. }
| TraitValueMethod { sig: id, .. }
| ValueMethod { sig: id, .. }
| External { sig: id, .. }
| Pure(id) => Some(*id),
}
}
Expand All @@ -546,12 +547,12 @@ impl CallType {
CallType::BuiltinFunction(f) => f.as_ref().into(),
CallType::Intrinsic(f) => f.as_ref().into(),
CallType::BuiltinValueMethod { method, .. } => method.as_ref().into(),
CallType::BuiltinAssociatedFunction { function, .. } => function.as_ref().into(),
CallType::AssociatedFunction { function: id, .. }
| CallType::ValueMethod { method: id, .. }
| CallType::External { function: id, .. }
CallType::BuiltinAssociatedFunction { sig: function, .. } => function.as_ref().into(),
CallType::AssociatedFunction { sig: id, .. }
| CallType::ValueMethod { sig: id, .. }
| CallType::External { sig: id, .. }
| CallType::Pure(id) => id.name(db),
CallType::TraitValueMethod { method: id, .. } => id.name(db),
CallType::TraitValueMethod { sig: id, .. } => id.name(db),
CallType::TypeConstructor(typ) => typ.display(db).to_string().into(),
CallType::EnumConstructor(variant) => {
let enum_name = variant.parent(db).name(db);
Expand All @@ -574,7 +575,9 @@ impl CallType {
false
}
} else {
self.function().map(|id| id.is_unsafe(db)).unwrap_or(false)
self.function_sig()
.map(|id| id.is_unsafe(db))
.unwrap_or(false)
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/analyzer/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ pub trait AnalyzerDb: SourceDb + Upcast<dyn SourceDb> + UpcastMut<dyn SourceDb>
fn module_is_incomplete(&self, module: ModuleId) -> bool;
#[salsa::invoke(queries::module::module_all_items)]
fn module_all_items(&self, module: ModuleId) -> Rc<[Item]>;
// Returns all functions defined in the module.
#[salsa::invoke(queries::module::module_all_functions)]
fn module_all_functions(&self, module: ModuleId) -> Rc<[FunctionId]>;
#[salsa::invoke(queries::module::module_all_impls)]
fn module_all_impls(&self, module: ModuleId) -> Rc<[ImplId]>;
#[salsa::invoke(queries::module::module_item_map)]
Expand Down
18 changes: 12 additions & 6 deletions crates/analyzer/src/db/queries/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,17 +396,23 @@ pub fn function_dependency_graph(db: &dyn AnalyzerDb, function: FunctionId) -> D
let body = function.body(db);
for calltype in body.calls.values() {
match calltype {
CallType::Pure(function) | CallType::AssociatedFunction { function, .. } => {
directs.push((root, Item::Function(*function), DepLocality::Local));
CallType::Pure(sig) | CallType::AssociatedFunction { sig, .. } => {
if let Some(func) = sig.function(db) {
directs.push((root, Item::Function(func), DepLocality::Local));
}
}
CallType::ValueMethod { method, .. } => {
directs.push((root, Item::Function(*method), DepLocality::Local));
CallType::ValueMethod { sig, .. } => {
if let Some(func) = sig.function(db) {
directs.push((root, Item::Function(func), DepLocality::Local));
}
}
CallType::TraitValueMethod { trait_id, .. } => {
directs.push((root, Item::Trait(*trait_id), DepLocality::Local));
}
CallType::External { contract, function } => {
directs.push((root, Item::Function(*function), DepLocality::External));
CallType::External { contract, sig } => {
if let Some(func) = sig.function(db) {
directs.push((root, Item::Function(func), DepLocality::External));
}
// Probably redundant:
directs.push((
root,
Expand Down
32 changes: 30 additions & 2 deletions crates/analyzer/src/db/queries/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::context::{Analysis, AnalyzerContext, Constant, NamedThing};
use crate::display::Displayable;
use crate::errors::{self, ConstEvalError, TypeError};
use crate::namespace::items::{
Contract, ContractId, Enum, Function, Impl, ImplId, Item, ModuleConstant, ModuleConstantId,
ModuleId, ModuleSource, Struct, StructId, Trait, TraitId, TypeAlias, TypeDef,
Contract, ContractId, Enum, Function, FunctionId, Impl, ImplId, Item, ModuleConstant,
ModuleConstantId, ModuleId, ModuleSource, Struct, StructId, Trait, TraitId, TypeAlias, TypeDef,
};
use crate::namespace::scopes::ItemScope;
use crate::namespace::types::{self, TypeId};
Expand Down Expand Up @@ -68,6 +68,9 @@ pub fn module_all_items(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[Item]> {
module,
})),
))),
ast::ModuleStmt::Extern(_) => {
todo!()
}
ast::ModuleStmt::Contract(node) => Some(Item::Type(TypeDef::Contract(
db.intern_contract(Rc::new(Contract {
name: node.name().into(),
Expand Down Expand Up @@ -106,6 +109,31 @@ pub fn module_all_items(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[Item]> {
.collect()
}

pub fn module_all_functions(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[FunctionId]> {
let mut funcs = vec![];
for item in module.all_items(db).iter() {
match item {
Item::Impl(id) => funcs.extend(id.all_functions(db).iter().copied()),
Item::Function(func) => funcs.push(*func),
Item::Type(def) => match def {
TypeDef::Contract(id) => {
funcs.extend(id.all_functions(db).iter().copied());
}
TypeDef::Struct(id) => {
funcs.extend(id.all_functions(db).iter().copied());
}
TypeDef::Enum(id) => {
funcs.extend(id.all_functions(db).iter().copied());
}
_ => {}
},
_ => {}
}
}

funcs.into_iter().collect()
}

pub fn module_all_impls(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[ImplId]> {
let body = &module.ast(db).body;
body.iter()
Expand Down
22 changes: 22 additions & 0 deletions crates/analyzer/src/namespace/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use std::rc::Rc;
use std::{fmt, ops::Deref};
use strum::IntoEnumIterator;

use super::types::Generic;

/// A named item. This does not include things inside of
/// a function body.
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
Expand Down Expand Up @@ -501,6 +503,10 @@ impl ModuleId {
db.module_all_items(*self)
}

pub fn all_functions(&self, db: &dyn AnalyzerDb) -> Rc<[FunctionId]> {
db.module_all_functions(*self)
}

/// Includes duplicate names
pub fn all_impls(&self, db: &dyn AnalyzerDb) -> Rc<[ImplId]> {
db.module_all_impls(*self)
Expand Down Expand Up @@ -1106,6 +1112,10 @@ impl FunctionSigId {
Item::Type(TypeDef::Contract(cid)) => Some(types::Type::SelfContract(cid).id(db)),
Item::Type(TypeDef::Struct(sid)) => Some(types::Type::Struct(sid).id(db)),
Item::Type(TypeDef::Enum(sid)) => Some(types::Type::Enum(sid).id(db)),
Item::Trait(_) => Some(db.intern_type(Type::Generic(Generic {
name: "Self".into(),
bounds: Rc::new([]),
}))),
Item::Impl(id) => Some(id.receiver(db)),
Item::Type(TypeDef::Primitive(ty)) => Some(db.intern_type(Type::Base(ty))),
_ => None,
Expand All @@ -1121,6 +1131,9 @@ impl FunctionSigId {
pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
self.is_trait_fn(db) || self.is_impl_fn(db) || self.pub_span(db).is_some()
}
pub fn is_unsafe(&self, db: &dyn AnalyzerDb) -> bool {
self.unsafe_span(db).is_some()
}
pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
self.data(db).ast.kind.name.kind.clone()
}
Expand Down Expand Up @@ -1154,6 +1167,11 @@ impl FunctionSigId {
Item::Type(TypeDef::Enum(id)) => id.function(db, &self.name(db)),
Item::Impl(id) => id.function(db, &self.name(db)),
Item::Type(TypeDef::Contract(id)) => id.function(db, &self.name(db)),
Item::Module(id) => id
.all_functions(db)
.iter()
.find(|id| id.sig(db) == *self)
.copied(),
_ => None,
}
}
Expand Down Expand Up @@ -1193,6 +1211,10 @@ impl FunctionSigId {
self.data(db).module
}

pub fn ingot(&self, db: &dyn AnalyzerDb) -> IngotId {
self.module(db).ingot(db)
}

pub fn is_contract_func(self, db: &dyn AnalyzerDb) -> bool {
matches! {self.parent(db), Item::Type(TypeDef::Contract(_))}
}
Expand Down
11 changes: 6 additions & 5 deletions crates/analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,10 @@ impl TypeId {
db.impl_for(*self, trait_)
}

/// Looks up all possible candidates of the given function name that are implemented via traits.
/// Groups results in two lists, the first contains all theoretical possible candidates and
/// the second contains only those that are actually callable because the trait is in scope.
/// Looks up all possible candidates of the given function name that are
/// implemented via traits. Groups results in two lists, the first
/// contains all theoretical possible candidates and the second contains
/// only those that are actually callable because the trait is in scope.
pub fn trait_function_candidates(
&self,
context: &mut dyn AnalyzerContext,
Expand Down Expand Up @@ -200,8 +201,8 @@ impl TypeId {
(candidates, in_scope_candidates)
}

/// Signature for the function with the given name defined directly on the type.
/// Does not consider trait impls.
/// Signature for the function with the given name defined directly on the
/// type. Does not consider trait impls.
pub fn function_sig(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
match self.typ(db) {
Type::SPtr(inner) => inner.function_sig(db, name),
Expand Down
Loading