Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sbillig committed May 7, 2022
1 parent d5c43d5 commit 322b7a3
Show file tree
Hide file tree
Showing 41 changed files with 310 additions and 474 deletions.
2 changes: 1 addition & 1 deletion crates/abi/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn contract_def(db: &dyn AnalyzerDb, contract: ContractId) -> Contract {
fn function_def(db: &dyn AnalyzerDb, name: &str, fn_id: FunctionId, typ: FuncType) -> Function {
let sig = fn_id.signature(db);
let inputs = sig
.external_params()
.params
.iter()
.map(|param| {
let typ = param.typ.clone().expect("function parameter type error");
Expand Down
2 changes: 2 additions & 0 deletions crates/analyzer/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ pub trait AnalyzerDb: SourceDb + Upcast<dyn SourceDb> + UpcastMut<dyn SourceDb>
fn module_parent_module(&self, module: ModuleId) -> Option<ModuleId>;
#[salsa::invoke(queries::module::module_submodules)]
fn module_submodules(&self, module: ModuleId) -> Rc<[ModuleId]>;
#[salsa::invoke(queries::module::module_get_context_struct_id)]
fn module_get_context_struct_id(&self, module: ModuleId) -> StructId;

// Module Constant
#[salsa::cycle(queries::module::module_constant_type_cycle)]
Expand Down
19 changes: 19 additions & 0 deletions crates/analyzer/src/db/queries/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,3 +595,22 @@ fn resolve_use_tree(
}
}
}

pub fn module_get_context_struct_id(db: &dyn AnalyzerDb, module: ModuleId) -> StructId {
// :D
if let Item::Type(TypeDef::Struct(id)) = module
.internal_items(db)
.get("std")
.expect("missing std module")
.items(db)
.get("context")
.expect("missing std::context module")
.items(db)
.get("Context")
.expect("missing std Context struct")
{
*id
} else {
panic!("std Context type isn't a struct")
}
}
5 changes: 5 additions & 0 deletions crates/analyzer/src/namespace/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,11 @@ impl ModuleId {
Ok(None)
}
}

pub fn context_type_id(&self, db: &dyn AnalyzerDb) -> StructId {
db.module_get_context_struct_id(*self)
}

pub fn submodules(&self, db: &dyn AnalyzerDb) -> Rc<[ModuleId]> {
db.module_submodules(*self)
}
Expand Down
25 changes: 0 additions & 25 deletions crates/analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,31 +404,6 @@ impl FunctionSignature {
pub fn expect_return_type(&self) -> FixedSize {
self.return_type.clone().expect("fn return type error")
}

/// Parameters without `ctx`, if it is a contract function that declares it.
///
/// This is used when calling a contract method externally.
pub fn external_params(&self) -> &[FunctionParam] {
if self.ctx_decl.is_some() {
&self.params[1..]
} else {
&self.params
}
}

/// Parameter types without `ctx`, if it is a contract function that
/// declares it.
///
/// This is used when calling a contract method externally.
///
/// # Panics
/// Panics if any param type is an `Err`
pub fn external_param_types(&self) -> Vec<FixedSize> {
self.external_params()
.iter()
.map(|param| param.typ.clone().expect("fn param type error"))
.collect()
}
}

impl Type {
Expand Down
1 change: 1 addition & 0 deletions crates/analyzer/src/traversal/call_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pub fn validate_named_args(
params: &[impl LabeledParameter],
) -> Result<(), FatalError> {
validate_arg_count(context, name, name_span, args, params.len(), "argument");
// TODO: if the first arg is missing, every other arg gets a label and type error

for (index, (param, arg)) in params.iter().zip(args.kind.iter()).enumerate() {
let expected_label = param.label();
Expand Down
68 changes: 8 additions & 60 deletions crates/analyzer/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1141,15 +1141,9 @@ fn expr_call_type_constructor(
_ => {}
}

if matches!(typ, Type::Contract(_)) {
validate_arg_count(context, &format!("{}", typ), name_span, args, 2, "argument");
expect_no_label_on_arg(context, args, 0);
expect_no_label_on_arg(context, args, 1);
} else {
// These all expect 1 arg, for now.
validate_arg_count(context, &format!("{}", typ), name_span, args, 1, "argument");
expect_no_label_on_arg(context, args, 0);
}
// These all expect 1 arg, for now.
validate_arg_count(context, &format!("{}", typ), name_span, args, 1, "argument");
expect_no_label_on_arg(context, args, 0);

let expr_attrs = match &typ {
Type::String(string_type) => {
Expand All @@ -1160,50 +1154,10 @@ fn expr_call_type_constructor(
ExpressionAttributes::new(typ.clone(), Location::Memory)
}
Type::Contract(_) => {
if let Some(first_arg) = &args.kind.get(0) {
let first_arg_attr = assignable_expr(context, &first_arg.kind.value, None)?;
if let Some(context_type) = context.get_context_type() {
if first_arg_attr.typ != Type::Struct(context_type.clone()) {
context.type_error(
"type mismatch",
first_arg.span,
&context_type,
&first_arg_attr.typ,
);
}
} else {
context.fancy_error(
"`Context` is not defined",
vec![
Label::primary(
args.span,
"`ctx` must be defined and passed into the contract constructor",
),
Label::secondary(
context.parent_function().name_span(context.db()),
"Note: declare `ctx` in this function signature",
),
Label::secondary(
context.parent_function().name_span(context.db()),
"Example: `pub fn foo(ctx: Context, ...)`",
),
],
vec![
"Note: import context with `use std::context::Context`".into(),
"Example: MyContract(ctx, contract_address)".into(),
],
);
}
}
if let Some(second_arg) = &args.kind.get(1) {
let second_arg_attr = assignable_expr(context, &second_arg.kind.value, None)?;
if second_arg_attr.typ != Type::Base(Base::Address) {
context.type_error(
"type mismatch",
second_arg.span,
&Base::Address,
&second_arg_attr.typ,
);
if let Some(arg) = &args.kind.get(0) {
let arg_attr = assignable_expr(context, &arg.kind.value, None)?;
if arg_attr.typ != Type::Base(Base::Address) {
context.type_error("type mismatch", arg.span, &Base::Address, &arg_attr.typ);
}
}
ExpressionAttributes::new(typ.clone(), Location::Value)
Expand Down Expand Up @@ -1391,13 +1345,7 @@ fn expr_call_method(
}

let sig = method.signature(context.db());

let params = if is_self {
&sig.params
} else {
sig.external_params()
};
validate_named_args(context, &field.kind, field.span, args, params)?;
validate_named_args(context, &field.kind, field.span, args, &sig.params)?;

let calltype = match class {
Class::Contract(contract) => {
Expand Down
3 changes: 0 additions & 3 deletions crates/analyzer/tests/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,9 @@ test_file! { ctx_init }
test_file! { ctx_pure }
test_file! { ctx_undeclared }
test_file! { ctx_missing_internal_call }
test_file! { ctx_passed_external_call }
test_file! { ctx_missing_create }
test_file! { ctx_missing_load }
test_file! { ctx_missing_event }
test_file! { ctx_builtins_param_incorrect_type }
test_file! { ctx_undefined_contract_init }
test_file! { ctx_undefined_create }
test_file! { ctx_undefined_create2 }
test_file! { ctx_undefined_event }
87 changes: 35 additions & 52 deletions crates/analyzer/tests/snapshots/analysis__external_contract.snap
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ note:
22 │ │ foo_address: address,
23 │ │ my_num: u256,
· │
27 │ │ let foo: Foo = Foo(ctx, foo_address)
28 │ │ foo.emit_event(my_num, my_addrs, my_string)
│ ╰───────────────────────────────────────────────────^ attributes hash: 11744736773867210426
27 │ │ let foo: Foo = Foo(foo_address)
28 │ │ foo.emit_event(ctx, my_num, my_addrs, my_string)
│ ╰────────────────────────────────────────────────────────^ attributes hash: 11744736773867210426
= FunctionSignature {
self_decl: None,
Expand Down Expand Up @@ -325,65 +325,50 @@ note:
note:
┌─ external_contract.fe:27:18
27let foo: Foo = Foo(ctx, foo_address)
27let foo: Foo = Foo(foo_address)
^^^ Foo

note:
┌─ external_contract.fe:27:28
27let foo: Foo = Foo(ctx, foo_address)
^^^ ^^^^^^^^^^^ address: Value
│ │
Context: Memory
27let foo: Foo = Foo(foo_address)
^^^^^^^^^^^ address: Value

note:
┌─ external_contract.fe:27:24
27let foo: Foo = Foo(ctx, foo_address)
^^^^^^^^^^^^^^^^^^^^^ Foo: Value
28foo.emit_event(my_num, my_addrs, my_string)
^^^ ^^^^^^ ^^^^^^^^ ^^^^^^^^^ String<11>: Memory
│ │ │ │
│ │ │ Array<address, 5>: Memory
│ │ u256: Value
27let foo: Foo = Foo(foo_address)
^^^^^^^^^^^^^^^^ Foo: Value
28foo.emit_event(ctx, my_num, my_addrs, my_string)
^^^ ^^^ ^^^^^^ ^^^^^^^^ ^^^^^^^^^ String<11>: Memory
│ │ │ │ │
│ │ │ │ Array<address, 5>: Memory
│ │ │ u256: Value
│ │ Context: Memory
Foo: Value

note:
┌─ external_contract.fe:28:9
28foo.emit_event(my_num, my_addrs, my_string)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (): Value
28foo.emit_event(ctx, my_num, my_addrs, my_string)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (): Value

note:
┌─ external_contract.fe:30:5
30 │ ╭ pub fn call_build_array(
31 │ │ ctx: Context,
32 │ │ foo_address: address,
33 │ │ a: u256,
· │
36 │ │ let foo: Foo = Foo(ctx, foo_address)
37 │ │ return foo.build_array(a, b)
│ ╰────────────────────────────────────^ attributes hash: 14801245347360386258
31 │ │ foo_address: address,
32 │ │ a: u256,
33 │ │ b: u256,
34 │ │ ) -> Array<u256, 3>:
35 │ │ let foo: Foo = Foo(foo_address)
36 │ │ return foo.build_array(a, b)
│ ╰────────────────────────────────────^ attributes hash: 4627171240003453976
= FunctionSignature {
self_decl: None,
ctx_decl: Some(
Mutable,
),
ctx_decl: None,
params: [
FunctionParam {
label: None,
name: "ctx",
typ: Ok(
Struct(
Struct {
name: "Context",
field_count: 0,
},
),
),
},
FunctionParam {
label: None,
name: "foo_address",
Expand Down Expand Up @@ -429,34 +414,32 @@ note:
}

note:
┌─ external_contract.fe:36:18
┌─ external_contract.fe:35:18
36let foo: Foo = Foo(ctx, foo_address)
35let foo: Foo = Foo(foo_address)
^^^ Foo

note:
┌─ external_contract.fe:36:28
┌─ external_contract.fe:35:28
36let foo: Foo = Foo(ctx, foo_address)
^^^ ^^^^^^^^^^^ address: Value
│ │
Context: Memory
35let foo: Foo = Foo(foo_address)
^^^^^^^^^^^ address: Value

note:
┌─ external_contract.fe:36:24
┌─ external_contract.fe:35:24
36let foo: Foo = Foo(ctx, foo_address)
^^^^^^^^^^^^^^^^^^^^^ Foo: Value
37return foo.build_array(a, b)
35let foo: Foo = Foo(foo_address)
^^^^^^^^^^^^^^^^ Foo: Value
36return foo.build_array(a, b)
^^^ ^ ^ u256: Value
│ │ │
│ │ u256: Value
Foo: Value

note:
┌─ external_contract.fe:37:16
┌─ external_contract.fe:36:16
37return foo.build_array(a, b)
36return foo.build_array(a, b)
^^^^^^^^^^^^^^^^^^^^^ Array<u256, 3>: Memory


Loading

0 comments on commit 322b7a3

Please sign in to comment.