Skip to content

Commit

Permalink
fix: fix some remaining candid issues
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyan-dfinity committed Jan 19, 2024
1 parent 1401203 commit 88d2205
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ Updated to candid 0.10, ic-cdk 0.12, and ic-cdk-timers 0.6
They've always been stored with nanosecond precisions on Linux and Macos.
Now they are stored with nanosecond precision on Windows too.

### fix: support `import` for local did file

### fix: subtyping check reports the special opt rule as error

## Dependencies

### Motoko
Expand Down
48 changes: 32 additions & 16 deletions src/dfx/src/lib/models/canister.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,30 +338,40 @@ fn wasm_opt_level_convert(opt_level: WasmOptLevel) -> OptLevel {
}

fn separate_candid(path: &Path) -> DfxResult<(String, String)> {
use candid::pretty::candid::{compile, pp_args};
use candid::types::internal::TypeInner;
use candid_parser::{
pretty_parse,
types::{Dec, IDLProg},
};
let did = dfx_core::fs::read_to_string(path)?;
let prog = pretty_parse::<IDLProg>(path.to_str().unwrap(), &did)?;
let has_imports = prog
.decs
.iter()
.any(|dec| matches!(dec, Dec::ImportType(_) | Dec::ImportServ(_)));
let (env, actor) = check_candid_file(path)?;
let actor = actor.ok_or_else(|| anyhow!("provided candid file contains no main service"))?;
if let candid::types::internal::TypeInner::Class(args, ty) = actor.as_ref() {
use candid_parser::pretty::{
candid::{compile, pp_ty},
utils::{concat, enclose},
let actor = env.trace_type(&actor)?;
let has_init_args = matches!(actor.as_ref(), TypeInner::Class(_, _));
if has_imports || has_init_args {
let (init_args, serv) = match actor.as_ref() {
TypeInner::Class(args, ty) => (args.clone(), ty.clone()),
TypeInner::Service(_) => (vec![], actor),
_ => unreachable!(),
};

let actor = Some(ty.clone());
let service_did = compile(&env, &actor);
let doc = concat(args.iter().map(pp_ty), ",");
let init_args = enclose("(", doc, ")").pretty(80).to_string();
Ok((service_did, init_args))
let init_args = pp_args(&init_args).pretty(80).to_string();
let service = compile(&env, &Some(serv));
Ok((service, init_args))
} else {
// The original candid from builder output doesn't contain init_args
// Use it directly to avoid items reordering
let service_did = dfx_core::fs::read_to_string(path)?;
let init_args = String::from("()");
Ok((service_did, init_args))
// Keep the original did file to preserve comments
Ok((did, "()".to_string()))
}
}

#[context("{} is not a valid subtype of {}", specified_idl_path.display(), compiled_idl_path.display())]
fn check_valid_subtype(compiled_idl_path: &Path, specified_idl_path: &Path) -> DfxResult {
use candid::types::subtype::{subtype_with_config, OptReport};
let (mut env, opt_specified) =
check_candid_file(specified_idl_path).context("Checking specified candid file.")?;
let specified_type =
Expand All @@ -372,7 +382,13 @@ fn check_valid_subtype(compiled_idl_path: &Path, specified_idl_path: &Path) -> D
opt_compiled.expect("Compiled did file should contain some service interface");
let mut gamma = HashSet::new();
let specified_type = env.merge_type(env2, specified_type);
candid::types::subtype::subtype(&mut gamma, &env, &compiled_type, &specified_type)?;
subtype_with_config(
OptReport::Error,
&mut gamma,
&env,
&compiled_type,
&specified_type,
)?;
Ok(())
}

Expand Down

0 comments on commit 88d2205

Please sign in to comment.