diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index e340b0348b..4bd05ce94f 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -15,7 +15,7 @@ paste.workspace = true salsa.workspace = true serde-semver.workspace = true smol_str.workspace = true -rust-embed = { version = "8.5.0", features = ["debug-embed"] } +rust-embed = "8.5.0" toml = "0.8.8" tracing.workspace = true petgraph.workspace = true diff --git a/crates/common/src/ingot.rs b/crates/common/src/ingot.rs index fc65a7b6fb..fdb92439e8 100644 --- a/crates/common/src/ingot.rs +++ b/crates/common/src/ingot.rs @@ -201,16 +201,13 @@ impl Workspace { .directory() .expect("Config URL should have a directory"); - Some(Ingot::new( - db, - base_url.clone(), - None, - if base_url.scheme().contains("core") { - IngotKind::Core - } else { - IngotKind::Local - }, - )) + let kind = if base_url.scheme().contains("core") { + IngotKind::Core + } else { + IngotKind::Local + }; + + Some(Ingot::new(db, base_url.clone(), None, kind)) } else { // Make a standalone ingot if no config is found let base = location.directory().unwrap_or_else(|| location.clone()); diff --git a/crates/fe/tests/fixtures/cli_output/single_files/parse_error.snap b/crates/fe/tests/fixtures/cli_output/single_files/parse_error.snap index ff5a74bf05..bb8f0123a8 100644 --- a/crates/fe/tests/fixtures/cli_output/single_files/parse_error.snap +++ b/crates/fe/tests/fixtures/cli_output/single_files/parse_error.snap @@ -1,6 +1,5 @@ --- source: crates/fe/tests/cli_output.rs -assertion_line: 77 expression: output input_file: tests/fixtures/cli_output/single_files/parse_error.fe --- @@ -19,6 +18,15 @@ error[1-0001]: `if` expression requires a body 6 │ } │ ^ expected `{` +error[8-0000]: type mismatch + ┌─ parse_error.fe:4:8 + │ +4 │ if x > { // Missing comparison value + │ ╭────────^ +5 │ │ return true +6 │ │ } + │ ╰─────^ expected `bool`, but `{integer}` is given + error[8-0013]: returned type mismatch ┌─ parse_error.fe:5:9 │ diff --git a/crates/hir-analysis/src/diagnostics.rs b/crates/hir-analysis/src/diagnostics.rs index bb7950a54f..5582e5022b 100644 --- a/crates/hir-analysis/src/diagnostics.rs +++ b/crates/hir-analysis/src/diagnostics.rs @@ -514,7 +514,7 @@ impl DiagnosticVoucher for PathResDiag<'_> { } } - Self::AmbiguousTrait { primary, method_name, traits } => { + Self::AmbiguousTrait { primary, method_name, trait_insts } => { let method_name = method_name.data(db); let mut sub_diagnostics = vec![SubDiagnostic { style: LabelStyle::Primary, @@ -522,11 +522,10 @@ impl DiagnosticVoucher for PathResDiag<'_> { span: primary.resolve(db), }]; - for trait_ in traits { - let trait_name = trait_.name(db).unwrap().data(db); + for inst in trait_insts { sub_diagnostics.push(SubDiagnostic { style: LabelStyle::Secondary, - message: format!("candidate: `{trait_name}::{method_name}`"), + message: format!("candidate: `{}::{method_name}`", inst.pretty_print(db, false)), span: primary.resolve(db), }); } @@ -1859,10 +1858,12 @@ impl DiagnosticVoucher for BodyDiag<'_> { }]; for trait_ in traits { - let trait_name = trait_.name(db).unwrap().data(db); sub_diagnostics.push(SubDiagnostic { style: LabelStyle::Secondary, - message: format!("candidate: `{trait_name}::{method_name}`"), + message: format!( + "candidate: `{}::{method_name}`", + trait_.pretty_print(db, false) + ), span: primary.resolve(db), }); } diff --git a/crates/hir-analysis/src/name_resolution/diagnostics.rs b/crates/hir-analysis/src/name_resolution/diagnostics.rs index 60edaace2c..8522482ac3 100644 --- a/crates/hir-analysis/src/name_resolution/diagnostics.rs +++ b/crates/hir-analysis/src/name_resolution/diagnostics.rs @@ -84,7 +84,7 @@ pub enum PathResDiag<'db> { AmbiguousTrait { primary: DynLazySpan<'db>, method_name: IdentId<'db>, - traits: ThinVec>, + trait_insts: ThinVec>, }, InvisibleAmbiguousTrait { primary: DynLazySpan<'db>, diff --git a/crates/hir-analysis/src/name_resolution/method_selection.rs b/crates/hir-analysis/src/name_resolution/method_selection.rs index d1389b29ba..d08d51e390 100644 --- a/crates/hir-analysis/src/name_resolution/method_selection.rs +++ b/crates/hir-analysis/src/name_resolution/method_selection.rs @@ -1,14 +1,13 @@ -use common::indexmap::{IndexMap, IndexSet}; +use common::indexmap::IndexSet; use hir::hir_def::{scope_graph::ScopeId, IdentId, Trait}; -use itertools::Itertools; use rustc_hash::FxHashSet; use thin_vec::ThinVec; use crate::{ name_resolution::{available_traits_in_scope, is_scope_visible_from}, ty::{ + binder::Binder, canonical::{Canonical, Canonicalized, Solution}, - fold::TyFoldable, func_def::FuncDef, method_table::probe_method, trait_def::{impls_for_ty, TraitDef, TraitInstId, TraitMethod}, @@ -56,12 +55,14 @@ pub(crate) fn select_method_candidate<'db>( method_name: IdentId<'db>, scope: ScopeId<'db>, assumptions: PredicateListId<'db>, + trait_: Option>, ) -> Result, MethodSelectionError<'db>> { if receiver.value.is_ty_var(db) { return Err(MethodSelectionError::ReceiverTypeMustBeKnown); } - let candidates = assemble_method_candidates(db, receiver, method_name, scope, assumptions); + let candidates = + assemble_method_candidates(db, receiver, method_name, scope, assumptions, trait_); let selector = MethodSelector { db, @@ -80,6 +81,7 @@ fn assemble_method_candidates<'db>( method_name: IdentId<'db>, scope: ScopeId<'db>, assumptions: PredicateListId<'db>, + trait_: Option>, ) -> AssembledCandidates<'db> { CandidateAssembler { db, @@ -87,6 +89,7 @@ fn assemble_method_candidates<'db>( method_name, scope, assumptions, + trait_, candidates: AssembledCandidates::default(), } .assemble() @@ -102,12 +105,15 @@ struct CandidateAssembler<'db> { scope: ScopeId<'db>, /// The assumptions for the type bound in the current scope. assumptions: PredicateListId<'db>, + trait_: Option>, candidates: AssembledCandidates<'db>, } impl<'db> CandidateAssembler<'db> { fn assemble(mut self) -> AssembledCandidates<'db> { - self.assemble_inherent_method_candidates(); + if self.trait_.is_none() { + self.assemble_inherent_method_candidates(); + } self.assemble_trait_method_candidates(); self.candidates } @@ -125,24 +131,24 @@ impl<'db> CandidateAssembler<'db> { fn assemble_trait_method_candidates(&mut self) { let ingot = self.scope.ingot(self.db); - let mut table = UnificationTable::new(self.db); - let extracted_receiver_ty = self.receiver_ty.extract_identity(&mut table); - for &implementor in impls_for_ty(self.db, ingot, self.receiver_ty) { - let trait_def = implementor.skip_binder().trait_def(self.db); - self.insert_trait_method_cand(trait_def) + for &imp in impls_for_ty(self.db, ingot, self.receiver_ty) { + self.insert_trait_method_cand(imp.skip_binder().trait_(self.db)); } + let mut table = UnificationTable::new(self.db); + let extracted_receiver_ty = self.receiver_ty.extract_identity(&mut table); + for &pred in self.assumptions.list(self.db) { let snapshot = table.snapshot(); let self_ty = pred.self_ty(self.db); let self_ty = table.instantiate_to_term(self_ty); if table.unify(extracted_receiver_ty, self_ty).is_ok() { - self.insert_trait_method_cand_with_inst(pred.def(self.db), pred); + self.insert_trait_method_cand(pred); for super_trait in pred.def(self.db).super_traits(self.db) { let super_trait = super_trait.instantiate(self.db, pred.args(self.db)); - self.insert_trait_method_cand_with_inst(super_trait.def(self.db), super_trait); + self.insert_trait_method_cand(super_trait); } } @@ -150,20 +156,17 @@ impl<'db> CandidateAssembler<'db> { } } - fn insert_trait_method_cand(&mut self, trait_def: TraitDef<'db>) { - if let Some(&trait_method) = trait_def.methods(self.db).get(&self.method_name) { - self.candidates.insert_trait(trait_def, trait_method); - } + fn allow_trait(&self, trait_def: TraitDef<'db>) -> bool { + self.trait_.map(|t| t == trait_def).unwrap_or(true) } - fn insert_trait_method_cand_with_inst( - &mut self, - trait_def: TraitDef<'db>, - trait_inst: TraitInstId<'db>, - ) { + fn insert_trait_method_cand(&mut self, inst: TraitInstId<'db>) { + let trait_def = inst.def(self.db); + if !self.allow_trait(trait_def) { + return; + } if let Some(&trait_method) = trait_def.methods(self.db).get(&self.method_name) { - self.candidates - .insert_trait_with_inst(trait_def, trait_method, trait_inst); + self.candidates.traits.insert((inst, trait_method)); } } } @@ -234,15 +237,15 @@ impl<'db> MethodSelector<'db> { let traits = &self.candidates.traits; if traits.len() == 1 { - let (def, method) = traits.iter().next().unwrap(); - return Ok(self.find_inst(*def, *method)); + let (inst, method) = traits.iter().next().unwrap(); + return Ok(self.check_inst(*inst, *method)); } let available_traits = self.available_traits(); let visible_traits: Vec<_> = traits .iter() .copied() - .filter(|cand| available_traits.contains(&cand.0)) + .filter(|(inst, _method)| available_traits.contains(&inst.def(self.db))) .collect(); match visible_traits.len() { @@ -251,14 +254,17 @@ impl<'db> MethodSelector<'db> { Err(MethodSelectionError::NotFound) } else { // Suggests trait imports. - let traits = traits.iter().map(|(def, _)| def.trait_(self.db)).collect(); + let traits = traits + .iter() + .map(|(inst, _)| inst.def(self.db).trait_(self.db)) + .collect(); Err(MethodSelectionError::InvisibleTraitMethod(traits)) } } 1 => { let (def, method) = visible_traits[0]; - Ok(self.find_inst(def, method)) + Ok(self.check_inst(def, method)) } _ => Err(MethodSelectionError::AmbiguousTraitMethod( @@ -275,39 +281,14 @@ impl<'db> MethodSelector<'db> { /// checks if the goal is satisfiable given the current assumptions. /// Depending on the result, it either returns a confirmed trait method /// candidate or one that needs further confirmation. - /// - /// # Arguments - /// - /// * `def` - The trait definition. - /// * `method` - The trait method. - /// - /// # Returns - /// - /// A `Candidate` representing the found trait method instance. - fn find_inst(&self, def: TraitDef<'db>, method: TraitMethod<'db>) -> MethodCandidate<'db> { + fn check_inst(&self, inst: TraitInstId<'db>, method: TraitMethod<'db>) -> MethodCandidate<'db> { let mut table = UnificationTable::new(self.db); - let receiver = self.receiver.extract_identity(&mut table); - let receiver = table.instantiate_to_term(receiver); // xxx remove? - - // Check if we have a stored trait instance with associated type bindings - let cand = if let Some(&stored_inst) = self.candidates.trait_instances.get(&(def, method)) { - // Use the stored instance which includes associated type bindings - stored_inst - } else { - // Create a fresh instance without bindings - let inst_args = def - .params(self.db) - .iter() - .map(|ty| table.new_var_from_param(*ty)) - .collect_vec(); - TraitInstId::new(self.db, def, inst_args, IndexMap::new()) - }; - - // Unify receiver and method self. - method.instantiate_with_inst(&mut table, receiver, cand); + // Seed the table with receiver's canonical variables so that subsequent + // canonicalization can safely probe them. + let _ = self.receiver.extract_identity(&mut table); - let cand = cand.fold_with(&mut table); - let canonical_cand = Canonicalized::new(self.db, cand); + let canonical_cand = Canonicalized::new(self.db, inst); + let inst = table.instantiate_with_fresh_vars(Binder::bind(inst)); match is_goal_satisfiable( self.db, @@ -318,13 +299,13 @@ impl<'db> MethodSelector<'db> { GoalSatisfiability::Satisfied(solution) => { // Map back the solution to the current context. let solution = canonical_cand.extract_solution(&mut table, *solution); - - // Unify candidate to solution. - table.unify(cand, solution).unwrap(); + // Replace TyParams in the solved instance with fresh inference vars so + // downstream unification can bind them (e.g., T = u32). + let solution = table.instantiate_with_fresh_vars(Binder::bind(solution)); MethodCandidate::TraitMethod(TraitMethodCand::new( self.receiver - .canonicalize_solution(self.db, &mut table, cand), + .canonicalize_solution(self.db, &mut table, solution), method, )) } @@ -334,7 +315,7 @@ impl<'db> MethodSelector<'db> { | GoalSatisfiability::UnSat(_) => { MethodCandidate::NeedsConfirmation(TraitMethodCand::new( self.receiver - .canonicalize_solution(self.db, &mut table, cand), + .canonicalize_solution(self.db, &mut table, inst), method, )) } @@ -373,7 +354,7 @@ impl<'db> MethodSelector<'db> { #[derive(Debug, Clone, PartialEq, Eq, Hash, salsa::Update)] pub enum MethodSelectionError<'db> { AmbiguousInherentMethod(ThinVec>), - AmbiguousTraitMethod(ThinVec>), + AmbiguousTraitMethod(ThinVec>), NotFound, InvisibleInherentMethod(FuncDef<'db>), InvisibleTraitMethod(ThinVec>), @@ -383,27 +364,11 @@ pub enum MethodSelectionError<'db> { #[derive(Default)] struct AssembledCandidates<'db> { inherent_methods: FxHashSet>, - traits: IndexSet<(TraitDef<'db>, TraitMethod<'db>)>, - // Store trait instances with their associated type bindings - trait_instances: IndexMap<(TraitDef<'db>, TraitMethod<'db>), TraitInstId<'db>>, + traits: IndexSet<(TraitInstId<'db>, TraitMethod<'db>)>, } impl<'db> AssembledCandidates<'db> { fn insert_inherent_method(&mut self, method: FuncDef<'db>) { self.inherent_methods.insert(method); } - - fn insert_trait(&mut self, def: TraitDef<'db>, method: TraitMethod<'db>) { - self.traits.insert((def, method)); - } - - fn insert_trait_with_inst( - &mut self, - def: TraitDef<'db>, - method: TraitMethod<'db>, - inst: TraitInstId<'db>, - ) { - self.traits.insert((def, method)); - self.trait_instances.insert((def, method), inst); - } } diff --git a/crates/hir-analysis/src/name_resolution/path_resolver.rs b/crates/hir-analysis/src/name_resolution/path_resolver.rs index fecddab778..8730d43cb4 100644 --- a/crates/hir-analysis/src/name_resolution/path_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/path_resolver.rs @@ -172,7 +172,7 @@ impl<'db> PathResError<'db> { expected: ExpectedPathKind, ) -> Option> { let failed_at = self.failed_at; - let ident = failed_at.ident(db).to_opt()?; // xxx PathKind::QualifiedType + let ident = failed_at.ident(db).to_opt()?; // TODO: handle PathKind::QualifiedType let diag = match self.kind { PathResErrorKind::ParseError => return None, @@ -248,12 +248,11 @@ impl<'db> PathResError<'db> { candidates, } } - MethodSelectionError::AmbiguousTraitMethod(trait_defs) => { - let traits = trait_defs.into_iter().map(|d| d.trait_(db)).collect(); + MethodSelectionError::AmbiguousTraitMethod(trait_insts) => { PathResDiag::AmbiguousTrait { primary: span, method_name: ident, - traits, + trait_insts, } } MethodSelectionError::InvisibleInherentMethod(func) => { @@ -344,7 +343,7 @@ impl<'db> PathRes<'db> { PathRes::Func(ty) => PathRes::Func(f(ty)), PathRes::Const(ty) => PathRes::Const(f(ty)), PathRes::EnumVariant(v) => PathRes::EnumVariant(ResolvedVariant { ty: f(v.ty), ..v }), - // xxx map over candidate ty? + // TODO: map over candidate ty? PathRes::Method(ty, candidate) => PathRes::Method(f(ty), candidate), r @ (PathRes::Trait(_) | PathRes::Mod(_) | PathRes::FuncParam(..)) => r, } @@ -641,6 +640,7 @@ where ident, parent_scope, assumptions, + None, ) { Ok(cand) => { let r = PathRes::Method(ty, cand); diff --git a/crates/hir-analysis/src/ty/diagnostics.rs b/crates/hir-analysis/src/ty/diagnostics.rs index 36906e67b0..86bed675ad 100644 --- a/crates/hir-analysis/src/ty/diagnostics.rs +++ b/crates/hir-analysis/src/ty/diagnostics.rs @@ -316,7 +316,7 @@ pub enum BodyDiag<'db> { AmbiguousTrait { primary: DynLazySpan<'db>, method_name: IdentId<'db>, - traits: ThinVec>, + traits: ThinVec>, }, AmbiguousTraitInst { @@ -407,15 +407,12 @@ impl<'db> BodyDiag<'db> { } } - pub(super) fn ops_trait_not_implemented( + pub(super) fn ops_trait_not_implemented( db: &'db dyn HirAnalysisDb, span: DynLazySpan<'db>, ty: TyId<'db>, - ops: T, - ) -> Self - where - T: TraitOps, - { + ops: &dyn TraitOps, + ) -> Self { let ty = ty.pretty_print(db).to_string(); let op = ops.op_symbol(db); let trait_path = ops.trait_path(db); diff --git a/crates/hir-analysis/src/ty/normalize.rs b/crates/hir-analysis/src/ty/normalize.rs index a7f3f9ebca..b0aa844048 100644 --- a/crates/hir-analysis/src/ty/normalize.rs +++ b/crates/hir-analysis/src/ty/normalize.rs @@ -6,6 +6,7 @@ use std::collections::hash_map::Entry; +use common::indexmap::IndexMap; use hir::hir_def::{scope_graph::ScopeId, ImplTrait}; use rustc_hash::FxHashMap; @@ -124,11 +125,13 @@ impl<'db> TypeNormalizer<'db> { } // 3) Fall back to the general associated type search used by path resolution, - // but restrict results to the same trait as `assoc`. + // but restrict results to the same trait as `assoc` and deduplicate by + // the resulting type. If all viable candidates agree on a single type, + // normalize to that type. // Search by the trait's self type: `SelfTy::assoc.name`. // Normalize the trait's self type before candidate search. let self_ty = self.fold_ty(assoc.trait_.self_ty(self.db)); - let mut cands = find_associated_type( + let mut raw_cands = find_associated_type( self.db, self.scope, Canonical::new(self.db, self_ty), @@ -137,11 +140,28 @@ impl<'db> TypeNormalizer<'db> { ); // Keep only candidates from the same trait as `assoc`. - cands.retain(|(inst, _)| inst.def(self.db) == assoc.trait_.def(self.db)); - match cands.as_slice() { - [] => None, - // Unique candidate: return it if it actually changes the type - [(_, t)] if *t != ty => Some(*t), + raw_cands.retain(|(inst, _)| inst.def(self.db) == assoc.trait_.def(self.db)); + + // Deduplicate by normalized result type (to handle cases where multiple + // impls yield the same associated type, e.g., Output = Self for all impls). + let mut dedup: IndexMap, ()> = IndexMap::new(); + for (_, t) in raw_cands.into_iter() { + // Continue folding so nested associated types are also normalized + let norm_t = self.fold_ty(t); + dedup.entry(norm_t).or_insert(()); + } + + match dedup.len() { + 0 => None, + 1 => { + let (unique, _) = dedup.first().unwrap(); + // Only replace if we're actually making progress + if *unique != ty { + Some(*unique) + } else { + None + } + } _ => None, } } diff --git a/crates/hir-analysis/src/ty/trait_def.rs b/crates/hir-analysis/src/ty/trait_def.rs index f808eed6cc..2d5b831aa6 100644 --- a/crates/hir-analysis/src/ty/trait_def.rs +++ b/crates/hir-analysis/src/ty/trait_def.rs @@ -157,7 +157,6 @@ pub(crate) fn impls_for_ty<'db>( if table.unify(key, ty.base_ty(db)).is_ok() { cands.push(insts); } - table.rollback_to(snapshot); } @@ -396,6 +395,19 @@ pub struct TraitInstId<'db> { } impl<'db> TraitInstId<'db> { + pub fn with_fresh_vars( + db: &'db dyn HirAnalysisDb, + def: TraitDef<'db>, + table: &mut UnificationTable<'db>, + ) -> Self { + let args = def + .params(db) + .iter() + .map(|ty| table.new_var_from_param(*ty)) + .collect::>(); + Self::new(db, def, args, IndexMap::new()) + } + pub fn assoc_ty_bindings(self, db: &'db dyn HirAnalysisDb) -> Vec<(IdentId<'db>, TyId<'db>)> { self.assoc_type_bindings(db) .iter() @@ -506,6 +518,7 @@ pub struct TraitDef<'db> { #[salsa::tracked] impl<'db> TraitDef<'db> { + #[salsa::tracked(return_ref)] pub fn methods(self, db: &'db dyn HirAnalysisDb) -> IndexMap, TraitMethod<'db>> { let mut methods = IndexMap::, TraitMethod<'db>>::default(); for method in self.trait_(db).methods(db) { diff --git a/crates/hir-analysis/src/ty/trait_lower.rs b/crates/hir-analysis/src/ty/trait_lower.rs index 28ae6d4c70..ae0074efac 100644 --- a/crates/hir-analysis/src/ty/trait_lower.rs +++ b/crates/hir-analysis/src/ty/trait_lower.rs @@ -11,6 +11,7 @@ use salsa::Update; use super::{ binder::Binder, const_ty::ConstTyId, + fold::{TyFoldable, TyFolder}, func_def::FuncDef, trait_def::{does_impl_trait_conflict, Implementor, TraitDef, TraitInstId}, trait_resolution::PredicateListId, @@ -101,14 +102,26 @@ pub(crate) fn lower_impl_trait<'db>( }) .collect(); + // Merge trait associated type defaults into the implementor, but evaluated in + // the trait's own scope and then instantiated with this impl's concrete args + // (including Self). This ensures defaults like `type Output = Self` resolve + // to the implementor's concrete self type rather than remaining as `Self`. + let trait_scope = trait_.def(db).trait_(db).scope(); for t in trait_.def(db).trait_(db).types(db).iter() { let (Some(name), Some(default)) = (t.name.to_opt(), t.default) else { continue; }; - types - .entry(name) - .or_insert_with(|| lower_hir_ty(db, default, scope, assumptions)); + + types.entry(name).or_insert_with(|| { + // Lower the default in the trait scope so `Self` and trait params are visible + let lowered = lower_hir_ty(db, default, trait_scope, assumptions); + // Instantiate all trait parameters (including `Self` at idx 0) with + // this implementor's concrete arguments so `Self` becomes the impl's + // self type and other generics (if used) are substituted too. + Binder::bind(lowered).instantiate(db, trait_.args(db)) + }); } + let implementor = Implementor::new(db, trait_, params, types, impl_trait); Some(Binder::bind(implementor)) @@ -130,13 +143,37 @@ pub(crate) fn lower_trait_ref<'db>( match resolve_path(db, path, scope, assumptions, false) { Ok(PathRes::Trait(t)) => { let mut args = t.args(db).clone(); + + // Substitute all occurrences of `Self` with `self_ty` + // TODO: this shouldn't be necessary; Self should resolve to self_ty in a later stage, + // but something seems to be broken. + struct SelfSubst<'db> { + db: &'db dyn HirAnalysisDb, + self_ty: TyId<'db>, + } + impl<'db> TyFolder<'db> for SelfSubst<'db> { + fn db(&self) -> &'db dyn HirAnalysisDb { + self.db + } + fn fold_ty(&mut self, ty: TyId<'db>) -> TyId<'db> { + match ty.data(self.db) { + TyData::TyParam(p) if p.is_trait_self() => self.self_ty, + _ => ty.super_fold_with(self), + } + } + } + + let mut folder = SelfSubst { db, self_ty }; args[0] = self_ty; - Ok(TraitInstId::new( - db, - t.def(db), - args, - t.assoc_type_bindings(db), - )) + args.iter_mut() + .skip(1) + .for_each(|a| *a = a.fold_with(&mut folder)); + let mut assoc_bindings = t.assoc_type_bindings(db).clone(); + assoc_bindings + .iter_mut() + .for_each(|(_, ty)| *ty = (*ty).fold_with(&mut folder)); + + Ok(TraitInstId::new(db, t.def(db), args, assoc_bindings)) } Ok(res) => Err(TraitRefLowerError::InvalidDomain(res)), Err(e) => Err(TraitRefLowerError::PathResError(e)), diff --git a/crates/hir-analysis/src/ty/trait_resolution/proof_forest.rs b/crates/hir-analysis/src/ty/trait_resolution/proof_forest.rs index 1087f743d8..1f56f589d9 100644 --- a/crates/hir-analysis/src/ty/trait_resolution/proof_forest.rs +++ b/crates/hir-analysis/src/ty/trait_resolution/proof_forest.rs @@ -361,7 +361,7 @@ impl GeneratorNode { let mut table = g_node.table.clone(); let gen_cand = table.instantiate_with_fresh_vars(cand); - // xxx require candidates to be pre-normalized + // TODO: require candidates to be pre-normalized // Normalize trait instance arguments before unification let normalized_gen_cand = { let trait_inst = gen_cand.trait_(db); diff --git a/crates/hir-analysis/src/ty/ty_check/callable.rs b/crates/hir-analysis/src/ty/ty_check/callable.rs index 26da2743a5..d5d531313a 100644 --- a/crates/hir-analysis/src/ty/ty_check/callable.rs +++ b/crates/hir-analysis/src/ty/ty_check/callable.rs @@ -13,7 +13,7 @@ use super::{ExprProp, TyChecker}; use crate::{ ty::{ diagnostics::{BodyDiag, FuncBodyDiag}, - fold::{TyFoldable, TyFolder}, + fold::{AssocTySubst, TyFoldable, TyFolder}, func_def::FuncDef, trait_def::TraitInstId, trait_resolution::constraint::collect_func_def_constraints, @@ -28,6 +28,9 @@ use crate::{ pub struct Callable<'db> { pub func_def: FuncDef<'db>, generic_args: Vec>, + /// The originating trait instance if this callable comes from a trait method + /// (e.g., operator overloading, method call, indexing). None for inherent functions. + pub trait_inst: Option>, } impl<'db> TyVisitable<'db> for Callable<'db> { @@ -35,7 +38,10 @@ impl<'db> TyVisitable<'db> for Callable<'db> { where V: TyVisitor<'db> + ?Sized, { - self.generic_args.visit_with(visitor) + self.generic_args.visit_with(visitor); + if let Some(inst) = self.trait_inst { + inst.visit_with(visitor); + } } } @@ -47,6 +53,7 @@ impl<'db> TyFoldable<'db> for Callable<'db> { Self { func_def: self.func_def, generic_args: self.generic_args.fold_with(folder), + trait_inst: self.trait_inst.map(|i| i.fold_with(folder)), } } } @@ -56,6 +63,7 @@ impl<'db> Callable<'db> { db: &'db dyn HirAnalysisDb, ty: TyId<'db>, span: DynLazySpan<'db>, + trait_inst: Option>, ) -> Result> { let (base, args) = ty.decompose_ty_app(db); @@ -73,6 +81,7 @@ impl<'db> Callable<'db> { Ok(Self { func_def: *func_def, generic_args: args.to_vec(), + trait_inst, }) } @@ -80,13 +89,29 @@ impl<'db> Callable<'db> { &self.generic_args } + pub fn trait_inst(&self) -> Option> { + self.trait_inst + } + pub fn ret_ty(&self, db: &'db dyn HirAnalysisDb) -> TyId<'db> { - self.func_def.ret_ty(db).instantiate(db, &self.generic_args) + let ret = self.func_def.ret_ty(db).instantiate(db, &self.generic_args); + if let Some(inst) = self.trait_inst { + let mut subst = AssocTySubst::new(db, inst); + ret.fold_with(&mut subst) + } else { + ret + } } pub fn ty(&self, db: &'db dyn HirAnalysisDb) -> TyId<'db> { - let ty = TyId::func(db, self.func_def); - TyId::foldl(db, ty, &self.generic_args) + let mut ty = TyId::func(db, self.func_def); + ty = TyId::foldl(db, ty, &self.generic_args); + if let Some(inst) = self.trait_inst { + let mut subst = AssocTySubst::new(db, inst); + ty.fold_with(&mut subst) + } else { + ty + } } pub(super) fn unify_generic_args( @@ -188,7 +213,11 @@ impl<'db> Callable<'db> { } } - let expected = expected.instantiate(db, &self.generic_args); + let mut expected = expected.instantiate(db, &self.generic_args); + if let Some(inst) = self.trait_inst { + let mut subst = AssocTySubst::new(db, inst); + expected = expected.fold_with(&mut subst); + } let expected = tc.normalize_ty(expected); tc.equate_ty(given.expr_prop.ty, expected, given.expr_span); } diff --git a/crates/hir-analysis/src/ty/ty_check/env.rs b/crates/hir-analysis/src/ty/ty_check/env.rs index 65459f6762..88814d6982 100644 --- a/crates/hir-analysis/src/ty/ty_check/env.rs +++ b/crates/hir-analysis/src/ty/ty_check/env.rs @@ -5,6 +5,7 @@ use hir::{ }, span::DynLazySpan, }; + use num_bigint::BigUint; use rustc_hash::FxHashMap; use salsa::Update; @@ -16,14 +17,15 @@ use crate::{ canonical::{Canonical, Canonicalized}, const_ty::{ConstTyData, ConstTyId, EvaluatedConstTy}, diagnostics::{BodyDiag, FuncBodyDiag, TraitConstraintDiag, TyDiagCollection}, - fold::{TyFoldable, TyFolder}, + fold::{AssocTySubst, TyFoldable, TyFolder}, func_def::{lower_func, FuncDef}, + normalize::normalize_ty, trait_def::TraitInstId, trait_resolution::{ constraint::collect_func_def_constraints, is_goal_satisfiable, GoalSatisfiability, PredicateListId, }, - ty_def::{InvalidCause, TyData, TyId, TyVarSort}, + ty_def::{InvalidCause, TyBase, TyData, TyId, TyVarSort}, ty_lower::lower_hir_ty, unify::UnificationTable, }, @@ -38,7 +40,7 @@ pub(super) struct TyCheckEnv<'db> { expr_ty: FxHashMap>, callables: FxHashMap>, - pending_confirmations: Vec<(TraitInstId<'db>, DynLazySpan<'db>)>, + deferred: Vec>, var_env: Vec>, pending_vars: FxHashMap, LocalBinding<'db>>, @@ -58,7 +60,7 @@ impl<'db> TyCheckEnv<'db> { pat_ty: FxHashMap::default(), expr_ty: FxHashMap::default(), callables: FxHashMap::default(), - pending_confirmations: Vec::new(), + deferred: Vec::new(), var_env: vec![BlockEnv::new(func.scope(), 0)], pending_vars: FxHashMap::default(), loop_stack: Vec::new(), @@ -244,7 +246,11 @@ impl<'db> TyCheckEnv<'db> { } pub(super) fn register_confirmation(&mut self, inst: TraitInstId<'db>, span: DynLazySpan<'db>) { - self.pending_confirmations.push((inst, span)) + self.deferred.push(DeferredTask::Confirm { inst, span }) + } + + pub(super) fn register_pending_method(&mut self, pending: PendingMethod<'db>) { + self.deferred.push(DeferredTask::Method(pending)) } /// Completes the type checking environment by finalizing pending trait @@ -272,7 +278,8 @@ impl<'db> TyCheckEnv<'db> { sink: &mut Vec>, ) -> TypedBody<'db> { let mut prober = Prober { table }; - self.perform_pending_confirmation(&mut prober, sink); + // Resolve all deferred tasks (confirmations + method disambiguations) + self.perform_deferred(&mut prober, sink); self.expr_ty .values_mut() @@ -322,86 +329,159 @@ impl<'db> TyCheckEnv<'db> { /// iteratively probing and unifying trait instances until a fixed point /// is reached. If any trait instance remains ambiguous, a diagnostic is /// generated and added to the diagnostics vector. - /// - /// # Arguments - /// - /// * `prober` - A mutable reference to the [`Prober`] used for type - /// unification and probing. - /// - /// # Returns - /// - /// * A vector of `FuncBodyDiag` containing diagnostics related to ambiguous - /// trait instances. - fn perform_pending_confirmation( - &self, + fn perform_deferred( + &mut self, prober: &mut Prober<'db, '_>, sink: &mut Vec>, ) { + let db = self.db; + let scope = self.scope(); let assumptions = self.assumptions(); - let mut changed = true; - let hir_db = self.db; - let ingot = self.body().top_mod(hir_db).ingot(hir_db); - // Try to perform confirmation until all pending confirmations reaches to - // the fixed point. - while changed { - changed = false; - for (inst, _) in &self.pending_confirmations { - let inst = inst.fold_with(prober); - let canonical_inst = Canonicalized::new(self.db, inst); - if let GoalSatisfiability::Satisfied(solution) = - is_goal_satisfiable(self.db, ingot, canonical_inst.value, assumptions) - { - let solution = canonical_inst.extract_solution(prober.table, *solution); - prober.table.unify(inst, solution).unwrap(); - - // We need compare old and new inst in a canonical form since a new inst might - // introduce new type variable in some cases. - // In other word, we need to check ⍺-equivalence to know whether the - // confirmation step move forward. - let new_canonical_inst = Canonical::new(self.db, inst.fold_with(prober.table)); - changed |= new_canonical_inst != canonical_inst.value; - } + let ingot = self.body().top_mod(db).ingot(db); + + let compute_return_ty = |prober: &mut Prober<'db, '_>, + recv_ty: TyId<'db>, + inst: TraitInstId<'db>, + method_name: IdentId<'db>| { + let trait_method = inst.def(db).methods(db).get(&method_name).unwrap(); + let func_ty = trait_method.instantiate_with_inst(prober.table, recv_ty, inst); + let (base, gen_args) = func_ty.decompose_ty_app(db); + let TyData::TyBase(TyBase::Func(func_def)) = base.data(db) else { + unreachable!(); + }; + let mut ret = func_def.ret_ty(db).instantiate(db, gen_args); + let mut subst = AssocTySubst::new(db, inst); + ret = ret.fold_with(&mut subst); + normalize_ty(db, ret, scope, assumptions) + }; + + let is_viable = |prober: &mut Prober<'db, '_>, + pending: &PendingMethod<'db>, + expr_ty: TyId<'db>, + inst: &TraitInstId<'db>| { + let snap = prober.table.snapshot(); + let recv_ty = pending.recv_ty.fold_with(prober); + let inst_self = prober.table.instantiate_to_term(inst.self_ty(db)); + if prober.table.unify(inst_self, recv_ty).is_err() { + prober.table.rollback_to(snap); + return false; } - } + let ret_ty = compute_return_ty(prober, recv_ty, *inst, pending.method_name); + let ok = prober.table.unify(expr_ty, ret_ty).is_ok(); + prober.table.rollback_to(snap); + ok + }; - // Finds ambiguous trait inst and emits diags. - for (inst, span) in &self.pending_confirmations { - let inst = inst.fold_with(prober); - let canonical_inst = Canonicalized::new(self.db, inst); - match is_goal_satisfiable(self.db, ingot, canonical_inst.value, assumptions) { - GoalSatisfiability::NeedsConfirmation(ambiguous) => { - let cands = ambiguous - .iter() - .map(|solution| canonical_inst.extract_solution(prober.table, *solution)) - .collect::>(); - - if !inst.self_ty(self.db).has_var(self.db) { - let diag = BodyDiag::AmbiguousTraitInst { - primary: span.clone(), - cands, - }; - sink.push(diag.into()) + // Fixed-point pass over deferred tasks + let mut progressed = true; + while progressed { + progressed = false; + let mut next: Vec> = Vec::new(); + for task in self.deferred.drain(..) { + match task { + DeferredTask::Confirm { inst, span } => { + let inst = inst.fold_with(prober); + let canonical_inst = Canonicalized::new(db, inst); + match is_goal_satisfiable(db, ingot, canonical_inst.value, assumptions) { + GoalSatisfiability::Satisfied(solution) => { + let solution = + canonical_inst.extract_solution(prober.table, *solution); + prober.table.unify(inst, solution).unwrap(); + let new_can = Canonical::new(db, inst.fold_with(prober.table)); + if new_can != canonical_inst.value { + progressed = true; + } + } + _ => next.push(DeferredTask::Confirm { inst, span }), + } + } + DeferredTask::Method(pending) => { + let recv_ty = pending.recv_ty.fold_with(prober); + let expr_ty = self.expr_ty[&pending.expr].ty.fold_with(prober); + if expr_ty.has_invalid(db) { + next.push(DeferredTask::Method(pending)); + continue; + } + let viable: Vec<_> = pending + .candidates + .iter() + .copied() + .filter(|inst| is_viable(prober, &pending, expr_ty, inst)) + .collect(); + if let [inst] = viable.as_slice() { + let ret_ty = + compute_return_ty(prober, recv_ty, *inst, pending.method_name); + prober.table.unify(expr_ty, ret_ty).unwrap(); + progressed = true; + } else { + next.push(DeferredTask::Method(pending)); + } } } + } + self.deferred = next; + } - GoalSatisfiability::UnSat(subgoal) => { - // Emit diagnostic for unsatisfied trait bound - // These are constraints that were explicitly registered for confirmation, - // not general WF checks, so we need to emit diagnostics for them - if !inst.self_ty(self.db).has_var(self.db) { - let unsat_subgoal = - subgoal.map(|s| canonical_inst.extract_solution(prober.table, s)); - let diag = TraitConstraintDiag::TraitBoundNotSat { - span: span.clone(), - primary_goal: inst, - unsat_subgoal, - }; - sink.push(TyDiagCollection::from(diag).into()) + // Emit diagnostics for remaining tasks + for task in self.deferred.drain(..) { + match task { + DeferredTask::Confirm { inst, span } => { + let inst = inst.fold_with(prober); + let canonical_inst = Canonicalized::new(db, inst); + match is_goal_satisfiable(db, ingot, canonical_inst.value, assumptions) { + GoalSatisfiability::NeedsConfirmation(ambiguous) => { + let cands = ambiguous + .iter() + .map(|s| canonical_inst.extract_solution(prober.table, *s)) + .collect::>(); + if !inst.self_ty(db).has_var(db) { + sink.push( + BodyDiag::AmbiguousTraitInst { + primary: span.clone(), + cands, + } + .into(), + ) + } + } + GoalSatisfiability::UnSat(subgoal) => { + if !inst.self_ty(db).has_var(db) { + let unsat = subgoal + .map(|s| canonical_inst.extract_solution(prober.table, s)); + sink.push( + TyDiagCollection::from(TraitConstraintDiag::TraitBoundNotSat { + span: span.clone(), + primary_goal: inst, + unsat_subgoal: unsat, + }) + .into(), + ) + } + } + _ => {} } } - - _ => { - // Other cases (Satisfied, ContainsInvalid) are handled elsewhere + DeferredTask::Method(pending) => { + let expr_ty = self.expr_ty[&pending.expr].ty.fold_with(prober); + if expr_ty.has_invalid(self.db) { + continue; + } + let viable: ThinVec<_> = pending + .candidates + .iter() + .copied() + .filter(|inst| is_viable(prober, &pending, expr_ty, inst)) + .collect(); + if viable.len() > 1 { + sink.push( + BodyDiag::AmbiguousTrait { + primary: pending.span.clone(), + method_name: pending.method_name, + traits: viable, + } + .into(), + ); + } } } } @@ -557,3 +637,20 @@ impl<'db> TyFolder<'db> for Prober<'db, '_> { } } } +#[derive(Debug, Clone)] +pub(super) struct PendingMethod<'db> { + pub expr: hir::hir_def::ExprId, + pub recv_ty: TyId<'db>, + pub method_name: hir::hir_def::IdentId<'db>, + pub candidates: Vec>, + pub span: DynLazySpan<'db>, +} + +#[derive(Debug, Clone)] +enum DeferredTask<'db> { + Confirm { + inst: TraitInstId<'db>, + span: DynLazySpan<'db>, + }, + Method(PendingMethod<'db>), +} diff --git a/crates/hir-analysis/src/ty/ty_check/expr.rs b/crates/hir-analysis/src/ty/ty_check/expr.rs index 1060a200d1..387e5e1959 100644 --- a/crates/hir-analysis/src/ty/ty_check/expr.rs +++ b/crates/hir-analysis/src/ty/ty_check/expr.rs @@ -1,7 +1,10 @@ +use std::panic; + +use common::ingot::IngotKind; use either::Either; use hir::hir_def::{ - ArithBinOp, BinOp, Expr, ExprId, FieldIndex, GenericArgListId, IdentId, Partial, Pat, PatId, - PathId, UnOp, VariantKind, + ArithBinOp, BinOp, Expr, ExprId, FieldIndex, IdentId, Partial, Pat, PatId, PathId, UnOp, + VariantKind, }; use super::{ @@ -9,20 +12,27 @@ use super::{ path::ResolvedPathInBody, RecordLike, Typeable, }; +use crate::ty::{ + diagnostics::{BodyDiag, FuncBodyDiag}, + fold::{AssocTySubst, TyFoldable as _}, + trait_def::TraitInstId, + ty_check::callable::Callable, + ty_def::{TyBase, TyData}, +}; +use crate::ty::{trait_def::TraitDef, trait_lower::lower_trait}; use crate::{ name_resolution::{ diagnostics::PathResDiag, is_scope_visible_from, method_selection::{select_method_candidate, MethodCandidate, MethodSelectionError}, - resolve_name_res, resolve_query, EarlyNameQueryId, ExpectedPathKind, NameDomain, - NameResBucket, PathRes, QueryDirective, + resolve_ident_to_bucket, resolve_name_res, resolve_path, resolve_query, EarlyNameQueryId, + ExpectedPathKind, NameDomain, NameResBucket, PathRes, QueryDirective, }, ty::{ canonical::Canonicalized, const_ty::ConstTyId, - diagnostics::{BodyDiag, FuncBodyDiag}, normalize::normalize_ty, - ty_check::{callable::Callable, path::RecordInitChecker, TyChecker}, + ty_check::{path::RecordInitChecker, TyChecker}, ty_def::{InvalidCause, TyId}, }, HirAnalysisDb, Spanned, @@ -43,14 +53,13 @@ impl<'db> TyChecker<'db> { Expr::Lit(lit) => ExprProp::new(self.lit_ty(lit), true), Expr::Block(..) => self.check_block(expr, expr_data, expected), Expr::Un(..) => self.check_unary(expr, expr_data), - Expr::Bin(..) => self.check_binary(expr, expr_data), + Expr::Bin(lhs, rhs, op) => self.check_binary(expr, *lhs, *rhs, *op), Expr::Call(..) => self.check_call(expr, expr_data), Expr::MethodCall(..) => self.check_method_call(expr, expr_data), Expr::Path(..) => self.check_path(expr, expr_data), Expr::RecordInit(..) => self.check_record_init(expr, expr_data), Expr::Field(..) => self.check_field(expr, expr_data), Expr::Tuple(..) => self.check_tuple(expr, expr_data, expected), - Expr::Index(..) => self.check_index(expr, expr_data), Expr::Array(..) => self.check_array(expr, expr_data, expected), Expr::ArrayRep(..) => self.check_array_rep(expr, expr_data, expected), Expr::If(..) => self.check_if(expr, expr_data), @@ -66,6 +75,11 @@ impl<'db> TyChecker<'db> { actual } + pub(super) fn check_expr_unknown(&mut self, expr: ExprId) -> ExprProp<'db> { + let t = self.fresh_ty(); + self.check_expr(expr, t) + } + fn check_block( &mut self, expr: ExprId, @@ -96,183 +110,95 @@ impl<'db> TyChecker<'db> { let Expr::Un(lhs, op) = expr_data else { unreachable!() }; - let Partial::Present(op) = op else { - return ExprProp::invalid(self.db); - }; - - let expr_ty = self.fresh_ty(); - let typed_expr = self.check_expr(*lhs, expr_ty); - let expr_ty = typed_expr.ty; - - if expr_ty.has_invalid(self.db) { + let prop = self.check_expr_unknown(*lhs); + if *op == UnOp::Plus { + // TODO: remove support for unary plus? what should it do? + return prop; + } + if prop.ty.has_invalid(self.db) { return ExprProp::invalid(self.db); } - match op { - UnOp::Plus | UnOp::Minus => { - if expr_ty.is_integral(self.db) { - return typed_expr; - } - } - - UnOp::Not => { - if expr_ty.is_bool(self.db) { - return typed_expr; - } - } - - UnOp::BitNot => { - if expr_ty.is_integral(self.db) { - return typed_expr; - } - } + if prop.ty.is_integral_var(self.db) && matches!(op, UnOp::Plus | UnOp::Minus | UnOp::BitNot) + { + return prop; } - let base_ty = expr_ty.base_ty(self.db); + let base_ty = prop.ty.base_ty(self.db); if base_ty.is_ty_var(self.db) { let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); self.push_diag(diag); return ExprProp::invalid(self.db); } - // TODO: We need to check if the type implements a trait corresponding to the - // operator when these traits are defined in `std`. - let diag = BodyDiag::ops_trait_not_implemented( - self.db, - expr.span(self.body()).into(), - expr_ty, - *op, - ); - self.push_diag(diag); - - ExprProp::invalid(self.db) + self.check_ops_trait(expr, prop.ty, op, None) } - fn check_binary(&mut self, expr: ExprId, expr_data: &Expr<'db>) -> ExprProp<'db> { - let Expr::Bin(lhs, rhs, op) = expr_data else { - unreachable!() - }; - let Partial::Present(op) = op else { - return ExprProp::invalid(self.db); - }; + fn check_binary( + &mut self, + expr: ExprId, + lhs_expr: ExprId, + rhs_expr: ExprId, + op: BinOp, + ) -> ExprProp<'db> { + // Logical operands must be bools + if matches!(op, BinOp::Logical(_)) { + let bool = TyId::bool(self.db); + let lhs = self.check_expr(lhs_expr, bool); + let rhs = self.check_expr(rhs_expr, bool); + return if lhs.ty.is_bool(self.db) && rhs.ty.is_bool(self.db) { + ExprProp::new(bool, true) + } else { + ExprProp::invalid(self.db) + }; + } - let lhs_ty = self.fresh_ty(); - let typed_lhs = self.check_expr(*lhs, lhs_ty); - let lhs_ty = typed_lhs.ty; - if lhs_ty.has_invalid(self.db) { + let lhs = self.check_expr_unknown(lhs_expr); + if lhs.ty.has_invalid(self.db) { return ExprProp::invalid(self.db); } - match op { - BinOp::Arith(arith_op) => { - use hir::hir_def::ArithBinOp::*; - - let typed_rhs = self.check_expr(*rhs, lhs_ty); - let rhs_ty = typed_rhs.ty; - if rhs_ty.has_invalid(self.db) { - return ExprProp::invalid(self.db); - } - - match arith_op { - Add | Sub | Mul | Div | Rem | Pow | LShift | RShift => { - if lhs_ty.is_integral(self.db) { - return typed_rhs; - } - } - - BitAnd | BitOr | BitXor => { - if lhs_ty.is_integral(self.db) | lhs_ty.is_bool(self.db) { - return typed_rhs; - } - } - } - } - - BinOp::Comp(comp_op) => { - use hir::hir_def::CompBinOp::*; - - let typed_rhs = self.check_expr(*rhs, lhs_ty); - let rhs_ty = typed_rhs.ty; - if rhs_ty.has_invalid(self.db) { - return ExprProp::invalid(self.db); - } - - match comp_op { - Eq | NotEq => { - if lhs_ty.is_integral(self.db) | lhs_ty.is_bool(self.db) { - let ty = TyId::bool(self.db); - return ExprProp::new(ty, true); - } - } - - Lt | LtEq | Gt | GtEq => { - if lhs_ty.is_integral(self.db) { - let ty = TyId::bool(self.db); - return ExprProp::new(ty, true); - } - } - } - } - - BinOp::Logical(logical_op) => { - use hir::hir_def::LogicalBinOp::*; - - let typed_rhs = self.check_expr(*rhs, lhs_ty); - let rhs_ty = typed_rhs.ty; - if rhs_ty.has_invalid(self.db) { - return ExprProp::invalid(self.db); - } - - match logical_op { - And | Or => { - if lhs_ty.is_bool(self.db) & rhs_ty.is_bool(self.db) { - let ty = TyId::bool(self.db); - return ExprProp::new(ty, true); - } - } - } - } + if matches!(op, BinOp::Index) && lhs.ty.is_array(self.db) { + // Built-in array indexing (TODO: move to trait impl) + let args = lhs.ty.generic_args(self.db); + let elem_ty = args[0]; + let index_ty = args[1].const_ty_ty(self.db).unwrap(); + self.check_expr(rhs_expr, index_ty); + return ExprProp::new(elem_ty, lhs.is_mut); + } else if lhs.ty.is_integral_var(self.db) { + // Avoid 'type must be known' diagnostics when lhs is an unknown integer ty + self.check_expr(rhs_expr, lhs.ty); + return lhs; } - let lhs_base_ty = lhs_ty.base_ty(self.db); - if lhs_base_ty.is_ty_var(self.db) { - let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); + // Fail if lhs ty is unknown + if lhs.ty.base_ty(self.db).is_ty_var(self.db) { + self.check_expr_unknown(rhs_expr); + let diag = BodyDiag::TypeMustBeKnown(lhs_expr.span(self.body()).into()); self.push_diag(diag); return ExprProp::invalid(self.db); } - // TODO: We need to check if the type implements a trait corresponding to the - // operator when these traits are defined in `std`. - let diag = BodyDiag::ops_trait_not_implemented( - self.db, - expr.span(self.body()).into(), - lhs_ty, - *op, - ); - self.push_diag(diag); - - ExprProp::invalid(self.db) + self.check_ops_trait(expr, lhs.ty, &op, Some(rhs_expr)) } fn check_call(&mut self, expr: ExprId, expr_data: &Expr<'db>) -> ExprProp<'db> { let Expr::Call(callee, args) = expr_data else { unreachable!() }; - let callee_ty = self.fresh_ty(); - let callee_ty = self.check_expr(*callee, callee_ty).ty; - + let callee_ty = self.check_expr_unknown(*callee).ty; if callee_ty.has_invalid(self.db) { return ExprProp::invalid(self.db); } - let mut callable = match Callable::new(self.db, callee_ty, callee.span(self.body()).into()) - { - Ok(callable) => callable, - Err(diag) => { - self.push_diag(diag); - return ExprProp::invalid(self.db); - } - }; + let mut callable = + match Callable::new(self.db, callee_ty, callee.span(self.body()).into(), None) { + Ok(callable) => callable, + Err(diag) => { + self.push_diag(diag); + return ExprProp::invalid(self.db); + } + }; let call_span = expr.span(self.body()).into_call_expr(); @@ -312,35 +238,62 @@ impl<'db> TyChecker<'db> { return ExprProp::invalid(self.db); }; - let receiver_prop = self.fresh_ty(); - let receiver_prop = self.check_expr(*receiver, receiver_prop); + let receiver_prop = self.check_expr_unknown(*receiver); if receiver_prop.ty.has_invalid(self.db) { return ExprProp::invalid(self.db); } - let assumptions = self.env.assumptions(); - let canonical_r_ty = Canonicalized::new(self.db, receiver_prop.ty); let candidate = match select_method_candidate( self.db, canonical_r_ty.value, method_name, self.env.scope(), - assumptions, + self.env.assumptions(), + None, ) { Ok(candidate) => candidate, - Err(diag) => { - let diag = body_diag_from_method_selection_err( - self.db, - diag, - Spanned::new( - canonical_r_ty.value.value, - receiver.span(self.body()).into(), - ), - Spanned::new(method_name, call_span.method_name().into()), - ); - self.push_diag(diag); - return ExprProp::invalid(self.db); + Err(err) => { + match err { + MethodSelectionError::AmbiguousTraitMethod(insts) => { + // Defer resolution using return-type constraints + let ret_ty = self.fresh_ty(); + let typed = ExprProp::new(ret_ty, true); + self.env.type_expr(expr, typed); + // Instantiate candidates with fresh inference vars so + // later unifications can bind their parameters. + let cands: Vec<_> = insts + .into_iter() + .map(|inst| { + self.table.instantiate_with_fresh_vars( + crate::ty::binder::Binder::bind(inst), + ) + }) + .collect(); + + self.env.register_pending_method(super::env::PendingMethod { + expr, + recv_ty: receiver_prop.ty, + method_name, + candidates: cands, + span: call_span.method_name().into(), + }); + return typed; + } + _ => { + let diag = body_diag_from_method_selection_err( + self.db, + err, + Spanned::new( + canonical_r_ty.value.value, + receiver.span(self.body()).into(), + ), + Spanned::new(method_name, call_span.method_name().into()), + ); + self.push_diag(diag); + return ExprProp::invalid(self.db); + } + } } }; @@ -352,9 +305,9 @@ impl<'db> TyChecker<'db> { MethodCandidate::TraitMethod(cand) => { let inst = canonical_r_ty.extract_solution(&mut self.table, cand.inst); - let trait_method = cand.method; let func_ty = - trait_method.instantiate_with_inst(&mut self.table, receiver_prop.ty, inst); + cand.method + .instantiate_with_inst(&mut self.table, receiver_prop.ty, inst); (func_ty, Some(inst)) } @@ -369,8 +322,12 @@ impl<'db> TyChecker<'db> { } }; - let mut callable = match Callable::new(self.db, func_ty, receiver.span(self.body()).into()) - { + let mut callable = match Callable::new( + self.db, + func_ty, + receiver.span(self.body()).into(), + trait_inst, + ) { Ok(callable) => callable, Err(diag) => { self.push_diag(diag); @@ -405,15 +362,6 @@ impl<'db> TyChecker<'db> { let ret_ty = callable.ret_ty(self.db); - // Apply associated type substitutions if this is a trait method - let ret_ty = if let Some(inst) = trait_inst { - use crate::ty::fold::{AssocTySubst, TyFoldable}; - let mut subst = AssocTySubst::new(self.db, inst); - ret_ty.fold_with(&mut subst) - } else { - ret_ty - }; - // Normalize the return type to resolve any associated types let normalized_ret_ty = self.normalize_ty(ret_ty); self.env.register_callable(expr, callable); @@ -755,43 +703,35 @@ impl<'db> TyChecker<'db> { ExprProp::new(ty, true) } - fn check_index(&mut self, expr: ExprId, expr_data: &Expr<'db>) -> ExprProp<'db> { - let Expr::Index(lhs, index) = expr_data else { - unreachable!() - }; - - let lhs_ty = self.fresh_ty(); - let typed_lhs = self.check_expr(*lhs, lhs_ty); - let lhs_ty = typed_lhs.ty; - let (lhs_base, args) = lhs_ty.decompose_ty_app(self.db); - - if lhs_base.is_ty_var(self.db) { - let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); - self.push_diag(diag); - return ExprProp::invalid(self.db); - } - - if lhs_base.has_invalid(self.db) { - return ExprProp::invalid(self.db); - } - - if lhs_base.is_array(self.db) { - let elem_ty = args[0]; - let index_ty = args[1].const_ty_ty(self.db).unwrap(); - self.check_expr(*index, index_ty); - return ExprProp::new(elem_ty, typed_lhs.is_mut); + /// Resolve a trait path like `core::ops::Index` by using the path's parent + /// as the module and the last segment as the trait name. Returns a base + /// trait instance whose generic args are the trait's own params + /// (placeholders), avoiding the need for explicit non-Self args. + fn resolve_core_trait(&self, trait_path: PathId<'db>) -> Option> { + let scope = self.env.scope(); + let assumptions = self.env.assumptions(); + let mut module_path = trait_path.parent(self.db)?; + + // If we are inside the core ingot, replace `core` with `ingot` in the trait path. + let ingot = self.env.body().top_mod(self.db).ingot(self.db); + if ingot.kind(self.db) == IngotKind::Core && trait_path.is_core_lib_path(self.db) { + module_path = module_path.replace_root( + IdentId::make_core(self.db), + IdentId::make_ingot(self.db), + self.db, + ); } + let trait_name = trait_path.ident(self.db).to_opt()?; + let Ok(PathRes::Mod(mod_scope)) = + resolve_path(self.db, module_path, scope, assumptions, false) + else { + panic!("failed to resolve `{}`", module_path.pretty_print(self.db)); + }; - // TODO: We need to check if the type implements the `Index` trait when `Index` - // is defined in `std`. - let diag = BodyDiag::ops_trait_not_implemented( - self.db, - expr.span(self.body()).into(), - lhs_ty, - IndexingOp {}, - ); - self.push_diag(diag); - ExprProp::invalid(self.db) + let bucket = + resolve_ident_to_bucket(self.db, PathId::from_ident(self.db, trait_name), mod_scope); + let nameres = bucket.pick(NameDomain::TYPE).as_ref().ok()?; + Some(lower_trait(self.db, nameres.trait_()?)) } fn check_array( @@ -930,7 +870,7 @@ impl<'db> TyChecker<'db> { for (i, is_reachable) in reachability.iter().enumerate() { if !is_reachable { let (_current_hir_pat, current_pat_id) = &hir_pats_with_ids[i]; - let diag = crate::ty::diagnostics::BodyDiag::UnreachablePattern { + let diag = BodyDiag::UnreachablePattern { primary: current_pat_id.span(self.body()).into(), }; self.push_diag(diag); @@ -945,7 +885,7 @@ impl<'db> TyChecker<'db> { self.env.scope(), scrutinee_ty, ) { - let diag = crate::ty::diagnostics::BodyDiag::NonExhaustiveMatch { + let diag = BodyDiag::NonExhaustiveMatch { primary: expr.span(self.body()).into(), scrutinee_ty, missing_patterns, @@ -973,57 +913,173 @@ impl<'db> TyChecker<'db> { } fn check_aug_assign(&mut self, expr: ExprId, expr_data: &Expr<'db>) -> ExprProp<'db> { - use ArithBinOp::*; - let Expr::AugAssign(lhs, rhs, op) = expr_data else { unreachable!() }; - let unit_ty = TyId::unit(self.db); + let unit = ExprProp::new(TyId::unit(self.db), true); - let lhs_ty = self.fresh_ty(); - let typed_lhs = self.check_expr(*lhs, lhs_ty); + let typed_lhs = self.check_expr_unknown(*lhs); let lhs_ty = typed_lhs.ty; if lhs_ty.has_invalid(self.db) { - return ExprProp::new(unit_ty, true); + return unit; } + self.check_assign_lhs(*lhs, &typed_lhs); - match op { - Add | Sub | Mul | Div | Rem | Pow | LShift | RShift => { - self.check_expr(*rhs, lhs_ty); - if lhs_ty.is_integral(self.db) { - self.check_assign_lhs(*lhs, &typed_lhs); - return ExprProp::new(unit_ty, true); - } - } - - BitAnd | BitOr | BitXor => { - self.check_expr(*rhs, lhs_ty); - if lhs_ty.is_integral(self.db) | lhs_ty.is_bool(self.db) { - self.check_assign_lhs(*lhs, &typed_lhs); - return ExprProp::new(unit_ty, true); - } - } + // Avoid 'type must be known' diagnostics for unknown integer ty + if lhs_ty.is_integral_var(self.db) { + self.check_expr(*rhs, lhs_ty); + return unit; } let lhs_base_ty = lhs_ty.base_ty(self.db); if lhs_base_ty.is_ty_var(self.db) { let diag = BodyDiag::TypeMustBeKnown(lhs.span(self.body()).into()); self.push_diag(diag); - return ExprProp::invalid(self.db); + return unit; } - // TODO: We need to check if the type implements a trait corresponding to the - // operator when these traits are defined in `std`. - let diag = BodyDiag::ops_trait_not_implemented( + self.check_ops_trait(expr, lhs_ty, &AugAssignOp(*op), Some(*rhs)); + + // Return unit ty even if trait resolution fails + unit + } + + /// Resolve a core::ops trait method for an operator on a given LHS type and + /// optionally check the RHS against the inferred method parameter type. + /// Returns the fully-instantiated function type and concrete trait instance. + fn check_ops_trait( + &mut self, + expr: ExprId, + lhs_ty: TyId<'db>, + op: &dyn TraitOps, + rhs_expr: Option, + ) -> ExprProp<'db> { + let Some(trait_def) = self.resolve_core_trait(op.trait_path(self.db)) else { + panic!("failed to resolve core::ops trait"); + }; + + let c_lhs_ty = Canonicalized::new(self.db, lhs_ty); + + let (method, inst) = match select_method_candidate( self.db, - expr.span(self.body()).into(), - lhs_ty, - AugAssignOp(*op), - ); - self.push_diag(diag); + c_lhs_ty.value, + op.trait_method(self.db), + self.env.scope(), + self.env.assumptions(), + Some(trait_def), + ) { + Ok(MethodCandidate::InherentMethod(_)) => unreachable!(), + Ok( + res @ (MethodCandidate::TraitMethod(cand) + | MethodCandidate::NeedsConfirmation(cand)), + ) => { + let inst = c_lhs_ty.extract_solution(&mut self.table, cand.inst); + if matches!(res, MethodCandidate::NeedsConfirmation(_)) { + self.env + .register_confirmation(inst, expr.span(self.body()).into()); + } - ExprProp::invalid(self.db) + let func_ty = cand + .method + .instantiate_with_inst(&mut self.table, lhs_ty, inst); + + if let Some(rhs_expr) = rhs_expr { + // Derive expected RHS type from the instantiated function type + let (base, gen_args) = func_ty.decompose_ty_app(self.db); + if let TyData::TyBase(TyBase::Func(func_def)) = base.data(self.db) { + let mut expected_rhs = + func_def.arg_tys(self.db)[1].instantiate(self.db, gen_args); + let mut subst = AssocTySubst::new(self.db, inst); + expected_rhs = self.normalize_ty(expected_rhs.fold_with(&mut subst)); + self.check_expr(rhs_expr, expected_rhs); + } + } + + (func_ty, inst) + } + Err(MethodSelectionError::AmbiguousTraitMethod(insts)) => { + let Some(rhs_expr) = rhs_expr else { + unreachable!("unary core::ops ambiguity"); + }; + + let rhs = self.check_expr_unknown(rhs_expr); + if rhs.ty.has_invalid(self.db) { + return ExprProp::invalid(self.db); + } + + let method_ident = op.trait_method(self.db); + let trait_method = trait_def.methods(self.db).get(&method_ident).unwrap(); + + let mut viable: Vec<(TyId<'db>, TraitInstId<'db>, TyId<'db>)> = Vec::new(); + for inst in insts.iter().copied() { + let snapshot = self.table.snapshot(); + let candidate_func_ty = + trait_method.instantiate_with_inst(&mut self.table, lhs_ty, inst); + let (base, gen_args) = candidate_func_ty.decompose_ty_app(self.db); + let expected_rhs = + if let TyData::TyBase(TyBase::Func(func_def)) = base.data(self.db) { + let mut subst = AssocTySubst::new(self.db, inst); + let ty = func_def.arg_tys(self.db)[1].instantiate(self.db, gen_args); + self.normalize_ty(ty.fold_with(&mut subst)) + } else { + unreachable!("candidate func ty should be a func"); + }; + let unifies = self.table.unify(rhs.ty, expected_rhs).is_ok(); + self.table.rollback_to(snapshot); + if unifies { + viable.push((candidate_func_ty, inst, expected_rhs)); + } + } + + match viable.len() { + 0 => { + let diag = BodyDiag::ops_trait_not_implemented( + self.db, + expr.span(self.body()).into(), + lhs_ty, + op, + ); + self.push_diag(diag); + return ExprProp::invalid(self.db); + } + 1 => { + let (func_ty, inst, expected_rhs) = viable.pop().unwrap(); + self.env + .register_confirmation(inst, expr.span(self.body()).into()); + self.unify_ty(Typeable::Expr(rhs_expr, rhs), rhs.ty, expected_rhs); + (func_ty, inst) + } + _ => { + self.push_diag(BodyDiag::AmbiguousTraitInst { + primary: expr.span(self.body()).into(), + cands: viable.into_iter().map(|(_, inst, _)| inst).collect(), + }); + return ExprProp::invalid(self.db); + } + } + } + Err(MethodSelectionError::NotFound) => { + let diag = BodyDiag::ops_trait_not_implemented( + self.db, + expr.span(self.body()).into(), + lhs_ty, + op, + ); + self.push_diag(diag); + return ExprProp::invalid(self.db); + } + Err(err) => { + unreachable!("unexpected error: {err:?}"); + } + }; + + let callable = Callable::new(self.db, method, expr.span(self.body()).into(), Some(inst)) + .expect("failed to create Callable for core::ops trait method"); + + let ret_ty = self.normalize_ty(callable.ret_ty(self.db)); + self.env.register_callable(expr, callable); + ExprProp::new(ret_ty, true) } fn check_assign_lhs(&mut self, lhs: ExprId, typed_lhs: &ExprProp<'db>) { @@ -1086,7 +1142,8 @@ impl<'db> TyChecker<'db> { }; match expr_data { - Expr::Field(lhs, ..) | Expr::Index(lhs, ..) => self.find_base_binding(*lhs), + Expr::Field(lhs, ..) => self.find_base_binding(*lhs), + Expr::Bin(lhs, _rhs, op) if *op == BinOp::Index => self.find_base_binding(*lhs), Expr::Path(..) => self.env.typed_expr(expr)?.binding(), _ => None, } @@ -1100,10 +1157,11 @@ impl<'db> TyChecker<'db> { return false; }; - matches!( - expr_data, - Expr::Path(..) | Expr::Field(..) | Expr::Index(..) - ) + match expr_data { + Expr::Path(..) | Expr::Field(..) => true, + Expr::Bin(_, _, op) if *op == BinOp::Index => true, + _ => false, + } } } @@ -1126,16 +1184,12 @@ fn body_diag_from_method_selection_err<'db>( .into() } - MethodSelectionError::AmbiguousTraitMethod(traits) => { - let traits = traits.into_iter().map(|def| def.trait_(db)).collect(); - - BodyDiag::AmbiguousTrait { - primary: method.span, - method_name: method.data, - traits, - } - .into() + MethodSelectionError::AmbiguousTraitMethod(traits) => BodyDiag::AmbiguousTrait { + primary: method.span, + method_name: method.data, + traits, } + .into(), MethodSelectionError::NotFound => { let base_ty = receiver.data.base_ty(db); @@ -1212,24 +1266,24 @@ fn resolve_ident_expr<'db>( /// This traits are intended to be implemented by the operators that can work as /// a syntax sugar for a trait method. For example, binary `+` operator /// implements this trait to be able to work as a syntax sugar for -/// `std::ops::Add` trait method. +/// `core::ops::Add` trait method. /// -/// TODO: We need to refine this trait definition to connect std library traits +/// TODO: We need to refine this trait definition to connect core library traits /// smoothly. pub(crate) trait TraitOps { fn trait_path<'db>(&self, db: &'db dyn HirAnalysisDb) -> PathId<'db> { - let path = std_ops_path(db); - path.push( - db, - Partial::Present(self.trait_name(db)), - GenericArgListId::none(db), - ) + let path = core_ops_path(db); + path.push_ident(db, self.trait_name(db)) } fn trait_name<'db>(&self, db: &'db dyn HirAnalysisDb) -> IdentId<'db> { self.triple(db)[0] } + fn trait_method<'db>(&self, db: &'db dyn HirAnalysisDb) -> IdentId<'db> { + self.triple(db)[1] + } + fn op_symbol<'db>(&self, db: &'db dyn HirAnalysisDb) -> IdentId<'db> { self.triple(db)[2] } @@ -1285,36 +1339,18 @@ impl TraitOps for BinOp { } } - BinOp::Logical(logical_op) => { - use hir::hir_def::LogicalBinOp::*; - - match logical_op { - And => ["And", "and", "&&"], - Or => ["Or", "or", "||"], - } + BinOp::Logical(_) => { + unreachable!() } + + BinOp::Index => ["Index", "index", "[]"], }; triple.map(|s| IdentId::new(db, s.to_string())) } } -struct IndexingOp {} - -impl TraitOps for IndexingOp { - fn triple<'db>(&self, db: &'db dyn HirAnalysisDb) -> [IdentId<'db>; 3] { - let name = "Index"; - let method_name = "index"; - let symbol = "[]"; - - [ - IdentId::new(db, name.to_string()), - IdentId::new(db, method_name.to_string()), - IdentId::new(db, symbol.to_string()), - ] - } -} - +#[derive(Clone, Copy, Debug)] struct AugAssignOp(ArithBinOp); impl TraitOps for AugAssignOp { @@ -1338,8 +1374,8 @@ impl TraitOps for AugAssignOp { } } -fn std_ops_path(db: &dyn HirAnalysisDb) -> PathId<'_> { - let std_ = IdentId::new(db, "std".to_string()); +fn core_ops_path(db: &dyn HirAnalysisDb) -> PathId<'_> { + let core = IdentId::new(db, "core".to_string()); let ops_ = IdentId::new(db, "ops".to_string()); - PathId::from_ident(db, std_).push_ident(db, ops_) + PathId::from_ident(db, core).push_ident(db, ops_) } diff --git a/crates/hir-analysis/src/ty/ty_def.rs b/crates/hir-analysis/src/ty/ty_def.rs index 12263a4dd3..60bfcc3a0e 100644 --- a/crates/hir-analysis/src/ty/ty_def.rs +++ b/crates/hir-analysis/src/ty/ty_def.rs @@ -92,6 +92,15 @@ impl<'db> TyId<'db> { } } + pub fn is_integral_var(self, db: &dyn HirAnalysisDb) -> bool { + match self.data(db) { + TyData::TyVar(var) => { + matches!(var.sort, TyVarSort::Integral) + } + _ => false, + } + } + /// Returns `true` if the type is a bool type. pub fn is_bool(self, db: &dyn HirAnalysisDb) -> bool { match self.data(db) { @@ -320,7 +329,6 @@ impl<'db> TyId<'db> { matches!(self.base_ty(db).data(db), TyData::TyBase(TyBase::Prim(_))) } - /// Returns `true` if the base type is a user defined `enum` type. pub(crate) fn as_enum(self, db: &'db dyn HirAnalysisDb) -> Option> { let base_ty = self.base_ty(db); if_chain! { diff --git a/crates/hir-analysis/src/ty/ty_lower.rs b/crates/hir-analysis/src/ty/ty_lower.rs index 602c4ec363..4ff4bc3cfa 100644 --- a/crates/hir-analysis/src/ty/ty_lower.rs +++ b/crates/hir-analysis/src/ty/ty_lower.rs @@ -233,7 +233,7 @@ pub(crate) fn lower_generic_arg_list<'db>( } GenericArg::AssocType(_assoc_type_arg) => { - // xxx + // TODO: ? TyId::invalid(db, InvalidCause::Other) } }) diff --git a/crates/hir-analysis/src/ty/unify.rs b/crates/hir-analysis/src/ty/unify.rs index 8531c039ff..d938522ae9 100644 --- a/crates/hir-analysis/src/ty/unify.rs +++ b/crates/hir-analysis/src/ty/unify.rs @@ -170,7 +170,15 @@ where _ => Err(UnificationError::TypeMismatch), } } - (TyData::AssocTy(t1), TyData::AssocTy(t2)) if t1 == t2 => Ok(()), + (TyData::AssocTy(a1), TyData::AssocTy(a2)) => { + if a1 == a2 { + Ok(()) + } else if a1.name == a2.name { + self.unify(a1.trait_, a2.trait_) + } else { + Err(UnificationError::TypeMismatch) + } + } (TyData::AssocTy(_), _) | (_, TyData::AssocTy(_)) => { // Associated types should be resolved before unification Err(UnificationError::TypeMismatch) diff --git a/crates/hir-analysis/test_files/pattern_matching/misc_tests/bindings.fe b/crates/hir-analysis/test_files/pattern_matching/misc_tests/bindings.fe index 4e0e5521ba..443f9f6e6d 100644 --- a/crates/hir-analysis/test_files/pattern_matching/misc_tests/bindings.fe +++ b/crates/hir-analysis/test_files/pattern_matching/misc_tests/bindings.fe @@ -83,7 +83,7 @@ fn test_conditional_type() -> i32 { } else { Option::None } - + match value { Option::Some(n) => n Option::None => 0 @@ -101,7 +101,7 @@ fn generic_match(opt: Option) -> bool { // Test nested generic patterns fn test_nested_generics() -> i32 { let nested: Option> = Option::Some(Result::Ok(42)) - + match nested { Option::Some(Result::Ok(val)) => val Option::Some(Result::Err(_)) => -1 @@ -123,7 +123,7 @@ fn test_match_expression() -> i32 { Option::Some(x) => x * 2 Option::None => 0 } - + result } @@ -131,7 +131,7 @@ fn test_match_expression() -> i32 { fn test_multiple_matches() -> i32 { let opt1 = Option::Some(10) let opt2 = Option::Some(20) - + let sum = match opt1 { Option::Some(a) => { match opt2 { @@ -146,7 +146,7 @@ fn test_multiple_matches() -> i32 { } } } - + sum } @@ -164,18 +164,18 @@ fn test_literal_patterns(opt: Option) -> i32 { fn test_different_instantiations() -> i32 { let int_opt: Option = Option::Some(42) let bool_opt: Option = Option::Some(true) - + let result1 = match int_opt { Option::Some(x) => x Option::None => 0 } - + let result2 = match bool_opt { Option::Some(true) => 1 Option::Some(false) => 0 Option::None => -1 } - + result1 + result2 } @@ -183,7 +183,7 @@ fn test_different_instantiations() -> i32 { fn test_unknown_error_type() -> i32 { // The Ok value has a literal, but Err type is unknown let result = Result::Ok(100) - + match result { Result::Ok(val) => val Result::Err(_) => 0 @@ -191,14 +191,14 @@ fn test_unknown_error_type() -> i32 { } // Generic function return without context -fn identity(value: T) -> T { +fn identity(_ value: T) -> T { value } fn test_generic_return() -> i32 { // The return type of identity can't be inferred without context let value = identity(Option::None) - + match value { Option::Some(x) => x Option::None => 0 @@ -209,10 +209,10 @@ fn test_generic_return() -> i32 { fn test_partial_generic_info() -> i32 { // Inner Option type can't be inferred let outer = Result::Ok(Option::None) - + match outer { Result::Ok(Option::Some(val)) => val Result::Ok(Option::None) => 0 Result::Err(_) => -1 } -} \ No newline at end of file +} diff --git a/crates/hir-analysis/test_files/pattern_matching/misc_tests/bindings.snap b/crates/hir-analysis/test_files/pattern_matching/misc_tests/bindings.snap index 4d0dd3381a..4989cc3f93 100644 --- a/crates/hir-analysis/test_files/pattern_matching/misc_tests/bindings.snap +++ b/crates/hir-analysis/test_files/pattern_matching/misc_tests/bindings.snap @@ -3,7 +3,7 @@ source: crates/hir-analysis/tests/pattern_matching.rs expression: diagnostic_output input_file: test_files/pattern_matching/misc_tests/bindings.fe --- -Misc test file bindings.fe has 11 diagnostic(s): +Misc test file bindings.fe has 12 diagnostic(s): error[8-0014]: type must be known here ┌─ bindings.fe:35:47 @@ -17,14 +17,14 @@ error[8-0014]: type must be known here 53 │ (Option::Some(a), Option::Some(b)) => a + b │ ^ type must be known here -error[8-0024]: argument label mismatch - ┌─ bindings.fe:200:26 - │ -194 │ fn identity(value: T) -> T { - │ -------- function defined here - · -200 │ let value = identity(Option::None) - │ ^^^^^^^^^^^^ expected `value` label +error[8-0031]: type annotation is needed + ┌─ bindings.fe:33:31 + │ +33 │ let pair = (Option::None, Option::None) + │ ^^^^^^^^^^^^ + │ │ + │ type annotation is needed + │ consider giving `: Option<_>` here error[8-0031]: type annotation is needed ┌─ bindings.fe:37:10 @@ -53,6 +53,15 @@ error[8-0031]: type annotation is needed │ type annotation is needed │ consider giving `: Option<_>` here +error[8-0031]: type annotation is needed + ┌─ bindings.fe:51:31 + │ +51 │ let pair = (Option::None, Option::Some(42)) + │ ^^^^^^^^^^^^^^^^ + │ │ + │ type annotation is needed + │ consider giving `: Option<{integer}>` here + error[8-0031]: type annotation is needed ┌─ bindings.fe:55:10 │ diff --git a/crates/hir-analysis/test_files/ty_check/test_assoc_type_subst.fe b/crates/hir-analysis/test_files/ty_check/assoc_type_subst.fe similarity index 99% rename from crates/hir-analysis/test_files/ty_check/test_assoc_type_subst.fe rename to crates/hir-analysis/test_files/ty_check/assoc_type_subst.fe index cff5cb7d14..daf57a6341 100644 --- a/crates/hir-analysis/test_files/ty_check/test_assoc_type_subst.fe +++ b/crates/hir-analysis/test_files/ty_check/assoc_type_subst.fe @@ -32,7 +32,7 @@ struct NestedImpl { impl Nested for NestedImpl { type Middle = SimpleImpl - + // Bug: Self::Middle::Output should resolve to T // but it's not properly substituting the type parameter fn get_nested(self) -> Self::Middle::Output { @@ -44,4 +44,4 @@ impl Nested for NestedImpl { fn test_nested() { let n: NestedImpl = NestedImpl { phantom: 0 } let result: u32 = n.get_nested() -} \ No newline at end of file +} diff --git a/crates/hir-analysis/test_files/ty_check/assoc_type_subst.snap b/crates/hir-analysis/test_files/ty_check/assoc_type_subst.snap index 594b0c3d6d..7a2775f666 100644 --- a/crates/hir-analysis/test_files/ty_check/assoc_type_subst.snap +++ b/crates/hir-analysis/test_files/ty_check/assoc_type_subst.snap @@ -1,10 +1,10 @@ --- source: crates/hir-analysis/tests/ty_check.rs expression: res -input_file: test_files/ty_check/test_assoc_type_subst.fe +input_file: test_files/ty_check/assoc_type_subst.fe --- note: - ┌─ test_assoc_type_subst.fe:18:34 + ┌─ assoc_type_subst.fe:18:34 │ 18 │ fn get(self) -> Self::Output { │ ╭──────────────────────────────────^ @@ -13,19 +13,19 @@ note: │ ╰─────^ T note: - ┌─ test_assoc_type_subst.fe:19:9 + ┌─ assoc_type_subst.fe:19:9 │ 19 │ self.value │ ^^^^ SimpleImpl note: - ┌─ test_assoc_type_subst.fe:19:9 + ┌─ assoc_type_subst.fe:19:9 │ 19 │ self.value │ ^^^^^^^^^^ T note: - ┌─ test_assoc_type_subst.fe:38:49 + ┌─ assoc_type_subst.fe:38:49 │ 38 │ fn get_nested(self) -> Self::Middle::Output { │ ╭─────────────────────────────────────────────────^ @@ -34,19 +34,19 @@ note: │ ╰─────^ T note: - ┌─ test_assoc_type_subst.fe:39:9 + ┌─ assoc_type_subst.fe:39:9 │ 39 │ todo() │ ^^^^ fn todo note: - ┌─ test_assoc_type_subst.fe:39:9 + ┌─ assoc_type_subst.fe:39:9 │ 39 │ todo() │ ^^^^^^ T note: - ┌─ test_assoc_type_subst.fe:44:18 + ┌─ assoc_type_subst.fe:44:18 │ 44 │ fn test_nested() { │ ╭──────────────────^ @@ -56,37 +56,38 @@ note: │ ╰─^ () note: - ┌─ test_assoc_type_subst.fe:45:9 + ┌─ assoc_type_subst.fe:45:9 │ 45 │ let n: NestedImpl = NestedImpl { phantom: 0 } │ ^ NestedImpl note: - ┌─ test_assoc_type_subst.fe:45:30 + ┌─ assoc_type_subst.fe:45:30 │ 45 │ let n: NestedImpl = NestedImpl { phantom: 0 } │ ^^^^^^^^^^^^^^^^^^^^^^^^^ NestedImpl note: - ┌─ test_assoc_type_subst.fe:45:52 + ┌─ assoc_type_subst.fe:45:52 │ 45 │ let n: NestedImpl = NestedImpl { phantom: 0 } │ ^ u32 note: - ┌─ test_assoc_type_subst.fe:46:9 + ┌─ assoc_type_subst.fe:46:9 │ 46 │ let result: u32 = n.get_nested() │ ^^^^^^ u32 note: - ┌─ test_assoc_type_subst.fe:46:23 + ┌─ assoc_type_subst.fe:46:23 │ 46 │ let result: u32 = n.get_nested() │ ^ NestedImpl note: - ┌─ test_assoc_type_subst.fe:46:23 + ┌─ assoc_type_subst.fe:46:23 │ 46 │ let result: u32 = n.get_nested() │ ^^^^^^^^^^^^^^ u32 + diff --git a/crates/hir-analysis/test_files/corelib/method_resolution.fe b/crates/hir-analysis/test_files/ty_check/core_method_resolution.fe similarity index 100% rename from crates/hir-analysis/test_files/corelib/method_resolution.fe rename to crates/hir-analysis/test_files/ty_check/core_method_resolution.fe diff --git a/crates/hir-analysis/test_files/ty_check/core_method_resolution.snap b/crates/hir-analysis/test_files/ty_check/core_method_resolution.snap new file mode 100644 index 0000000000..7b02f9ce23 --- /dev/null +++ b/crates/hir-analysis/test_files/ty_check/core_method_resolution.snap @@ -0,0 +1,123 @@ +--- +source: crates/hir-analysis/tests/ty_check.rs +expression: res +input_file: test_files/ty_check/core_method_resolution.fe +--- +note: + ┌─ core_method_resolution.fe:3:17 + │ + 3 │ fn f() -> usize { + │ ╭─────────────────^ + 4 │ │ let x = Option::Some(10) + 5 │ │ let y = Option::default() + 6 │ │ + · │ +11 │ │ } +12 │ │ } + │ ╰─^ usize + +note: + ┌─ core_method_resolution.fe:4:9 + │ +4 │ let x = Option::Some(10) + │ ^ Option + +note: + ┌─ core_method_resolution.fe:4:13 + │ +4 │ let x = Option::Some(10) + │ ^^^^^^^^^^^^ fn Some + +note: + ┌─ core_method_resolution.fe:4:13 + │ +4 │ let x = Option::Some(10) + │ ^^^^^^^^^^^^^^^^ Option + +note: + ┌─ core_method_resolution.fe:4:26 + │ +4 │ let x = Option::Some(10) + │ ^^ usize + +note: + ┌─ core_method_resolution.fe:5:9 + │ +5 │ let y = Option::default() + │ ^ Option + +note: + ┌─ core_method_resolution.fe:5:13 + │ +5 │ let y = Option::default() + │ ^^^^^^^^^^^^^^^ fn default> + +note: + ┌─ core_method_resolution.fe:5:13 + │ +5 │ let y = Option::default() + │ ^^^^^^^^^^^^^^^^^ Option + +note: + ┌─ core_method_resolution.fe:7:5 + │ + 7 │ ╭ if y.is_some() { + 8 │ │ y.unwrap() + 9 │ │ } else { +10 │ │ x.unwrap_or_default() +11 │ │ } + │ ╰─────^ usize + +note: + ┌─ core_method_resolution.fe:7:8 + │ +7 │ if y.is_some() { + │ ^ Option + +note: + ┌─ core_method_resolution.fe:7:8 + │ +7 │ if y.is_some() { + │ ^^^^^^^^^^^ bool + +note: + ┌─ core_method_resolution.fe:7:20 + │ +7 │ if y.is_some() { + │ ╭────────────────────^ +8 │ │ y.unwrap() +9 │ │ } else { + │ ╰─────^ usize + +note: + ┌─ core_method_resolution.fe:8:9 + │ +8 │ y.unwrap() + │ ^ Option + +note: + ┌─ core_method_resolution.fe:8:9 + │ +8 │ y.unwrap() + │ ^^^^^^^^^^ usize + +note: + ┌─ core_method_resolution.fe:9:12 + │ + 9 │ } else { + │ ╭────────────^ +10 │ │ x.unwrap_or_default() +11 │ │ } + │ ╰─────^ usize + +note: + ┌─ core_method_resolution.fe:10:9 + │ +10 │ x.unwrap_or_default() + │ ^ Option + +note: + ┌─ core_method_resolution.fe:10:9 + │ +10 │ x.unwrap_or_default() + │ ^^^^^^^^^^^^^^^^^^^^^ usize diff --git a/crates/hir-analysis/test_files/ty_check/debug_method_compare.fe b/crates/hir-analysis/test_files/ty_check/debug_method_compare.fe index 3958482991..9151e5bc70 100644 --- a/crates/hir-analysis/test_files/ty_check/debug_method_compare.fe +++ b/crates/hir-analysis/test_files/ty_check/debug_method_compare.fe @@ -5,7 +5,7 @@ extern { trait HasAssoc { type Output - + fn get_output(self) -> Self::Output } @@ -15,8 +15,8 @@ struct MyStruct { impl HasAssoc for MyStruct { type Output = T - + fn get_output(self) -> Self::Output { todo() } -} \ No newline at end of file +} diff --git a/crates/hir-analysis/test_files/ty_check/debug_nested_assoc.fe b/crates/hir-analysis/test_files/ty_check/debug_nested_assoc.fe index e1f1558d00..b5e2d623d1 100644 --- a/crates/hir-analysis/test_files/ty_check/debug_nested_assoc.fe +++ b/crates/hir-analysis/test_files/ty_check/debug_nested_assoc.fe @@ -30,4 +30,4 @@ fn test_generic() -> T::Assoc { fn test_call() { // This should resolve Generic::Assoc = u32 let y: u32 = test_generic>() -} \ No newline at end of file +} diff --git a/crates/hir-analysis/test_files/ty_check/debug_simple_assoc.fe b/crates/hir-analysis/test_files/ty_check/debug_simple_assoc.fe index dbe826d5d9..d378f4f92e 100644 --- a/crates/hir-analysis/test_files/ty_check/debug_simple_assoc.fe +++ b/crates/hir-analysis/test_files/ty_check/debug_simple_assoc.fe @@ -25,4 +25,4 @@ fn get_output() -> Simple::Output { fn test_function() { let y: u32 = get_output() -} \ No newline at end of file +} diff --git a/crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.fe b/crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.fe index ee4cb9acbf..9d658bff6b 100644 --- a/crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.fe +++ b/crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.fe @@ -1,3 +1,5 @@ +use core::todo + struct S { t: T, } @@ -24,11 +26,6 @@ impl Foo for S { } } -extern { - fn todo() -> ! -} - - fn bar() -> (u64, i32) { let s = S::new() diff --git a/crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.snap b/crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.snap index 12476bc1e8..779cb7fe4d 100644 --- a/crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.snap +++ b/crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.snap @@ -1,163 +1,163 @@ --- source: crates/hir-analysis/tests/ty_check.rs expression: res -input_file: crates/hir-analysis/test_files/ty_check/method/infer_by_constraints.fe +input_file: test_files/ty_check/method/infer_by_constraints.fe --- note: - ┌─ infer_by_constraints.fe:6:22 - │ -6 │ fn new() -> Self { - │ ╭──────────────────────^ -7 │ │ todo() -8 │ │ } - │ ╰─────^ S + ┌─ infer_by_constraints.fe:8:22 + │ + 8 │ fn new() -> Self { + │ ╭──────────────────────^ + 9 │ │ todo() +10 │ │ } + │ ╰─────^ S note: - ┌─ infer_by_constraints.fe:7:9 + ┌─ infer_by_constraints.fe:9:9 │ -7 │ todo() +9 │ todo() │ ^^^^ fn todo note: - ┌─ infer_by_constraints.fe:7:9 + ┌─ infer_by_constraints.fe:9:9 │ -7 │ todo() +9 │ todo() │ ^^^^^^ S note: - ┌─ infer_by_constraints.fe:16:30 + ┌─ infer_by_constraints.fe:18:30 │ -16 │ fn foo(self) -> (T, i32) { +18 │ fn foo(self) -> (T, i32) { │ ╭──────────────────────────────^ -17 │ │ (self.t, 1) -18 │ │ } +19 │ │ (self.t, 1) +20 │ │ } │ ╰─────^ (T, i32) note: - ┌─ infer_by_constraints.fe:17:9 + ┌─ infer_by_constraints.fe:19:9 │ -17 │ (self.t, 1) +19 │ (self.t, 1) │ ^^^^^^^^^^^ (T, i32) note: - ┌─ infer_by_constraints.fe:17:10 + ┌─ infer_by_constraints.fe:19:10 │ -17 │ (self.t, 1) +19 │ (self.t, 1) │ ^^^^ S note: - ┌─ infer_by_constraints.fe:17:10 + ┌─ infer_by_constraints.fe:19:10 │ -17 │ (self.t, 1) +19 │ (self.t, 1) │ ^^^^^^ T note: - ┌─ infer_by_constraints.fe:17:18 + ┌─ infer_by_constraints.fe:19:18 │ -17 │ (self.t, 1) +19 │ (self.t, 1) │ ^ i32 note: - ┌─ infer_by_constraints.fe:22:32 + ┌─ infer_by_constraints.fe:24:32 │ -22 │ fn foo(self) -> (u32, u32) { +24 │ fn foo(self) -> (u32, u32) { │ ╭────────────────────────────────^ -23 │ │ (1, 1) -24 │ │ } +25 │ │ (1, 1) +26 │ │ } │ ╰─────^ (u32, u32) note: - ┌─ infer_by_constraints.fe:23:9 + ┌─ infer_by_constraints.fe:25:9 │ -23 │ (1, 1) +25 │ (1, 1) │ ^^^^^^ (u32, u32) note: - ┌─ infer_by_constraints.fe:23:10 + ┌─ infer_by_constraints.fe:25:10 │ -23 │ (1, 1) +25 │ (1, 1) │ ^ u32 note: - ┌─ infer_by_constraints.fe:23:13 + ┌─ infer_by_constraints.fe:25:13 │ -23 │ (1, 1) +25 │ (1, 1) │ ^ u32 note: - ┌─ infer_by_constraints.fe:32:24 + ┌─ infer_by_constraints.fe:29:24 │ -32 │ fn bar() -> (u64, i32) { +29 │ fn bar() -> (u64, i32) { │ ╭────────────────────────^ -33 │ │ let s = S::new() -34 │ │ -35 │ │ let (x, y) = s.foo() -36 │ │ (x, y) -37 │ │ } +30 │ │ let s = S::new() +31 │ │ +32 │ │ let (x, y) = s.foo() +33 │ │ (x, y) +34 │ │ } │ ╰─^ (u64, i32) note: - ┌─ infer_by_constraints.fe:33:9 + ┌─ infer_by_constraints.fe:30:9 │ -33 │ let s = S::new() +30 │ let s = S::new() │ ^ S note: - ┌─ infer_by_constraints.fe:33:13 + ┌─ infer_by_constraints.fe:30:13 │ -33 │ let s = S::new() +30 │ let s = S::new() │ ^^^^^^ fn new note: - ┌─ infer_by_constraints.fe:33:13 + ┌─ infer_by_constraints.fe:30:13 │ -33 │ let s = S::new() +30 │ let s = S::new() │ ^^^^^^^^ S note: - ┌─ infer_by_constraints.fe:35:9 + ┌─ infer_by_constraints.fe:32:9 │ -35 │ let (x, y) = s.foo() +32 │ let (x, y) = s.foo() │ ^^^^^^ (u64, i32) note: - ┌─ infer_by_constraints.fe:35:10 + ┌─ infer_by_constraints.fe:32:10 │ -35 │ let (x, y) = s.foo() +32 │ let (x, y) = s.foo() │ ^ u64 note: - ┌─ infer_by_constraints.fe:35:13 + ┌─ infer_by_constraints.fe:32:13 │ -35 │ let (x, y) = s.foo() +32 │ let (x, y) = s.foo() │ ^ i32 note: - ┌─ infer_by_constraints.fe:35:18 + ┌─ infer_by_constraints.fe:32:18 │ -35 │ let (x, y) = s.foo() +32 │ let (x, y) = s.foo() │ ^ S note: - ┌─ infer_by_constraints.fe:35:18 + ┌─ infer_by_constraints.fe:32:18 │ -35 │ let (x, y) = s.foo() +32 │ let (x, y) = s.foo() │ ^^^^^^^ (u64, i32) note: - ┌─ infer_by_constraints.fe:36:5 + ┌─ infer_by_constraints.fe:33:5 │ -36 │ (x, y) +33 │ (x, y) │ ^^^^^^ (u64, i32) note: - ┌─ infer_by_constraints.fe:36:6 + ┌─ infer_by_constraints.fe:33:6 │ -36 │ (x, y) +33 │ (x, y) │ ^ u64 note: - ┌─ infer_by_constraints.fe:36:9 + ┌─ infer_by_constraints.fe:33:9 │ -36 │ (x, y) +33 │ (x, y) │ ^ i32 diff --git a/crates/hir-analysis/test_files/ty_check/ops.fe b/crates/hir-analysis/test_files/ty_check/ops.fe new file mode 100644 index 0000000000..01a8dcce16 --- /dev/null +++ b/crates/hir-analysis/test_files/ty_check/ops.fe @@ -0,0 +1,83 @@ +use core::ops::{Not, Add, Index, AddAssign, Eq} +use core::option::Option::{self, Some, None} + +enum Ok { + No, Yes +} + +impl Not for Ok { + fn not(self) -> Ok { + match self { + Ok::No => Ok::Yes + Ok::Yes => Ok::No + } + } +} + +fn flip(ok: Ok) -> Ok { + !ok +} + +impl Eq for Ok { + fn eq(self, _ other: Ok) -> bool { + match (self, other) { + (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + _ => false + } + } + fn ne(self, _ other: Ok) -> bool { + !self.eq(other) + } +} + +impl AddAssign for Ok { + fn add_assign(mut self, _ other: Ok) { + if other == Ok::Yes { + self = Ok::Yes + } + } +} + +struct Point { + x: i32, + y: i32, +} + +impl Add for Point { + fn add(self, _ p: Point) -> Point { + Point { + x: self.x + p.x, + y: self.y + p.y, + } + } +} + +impl Add for Point { + fn add(self, _ n: i32) -> Point { + Point { + x: self.x + n, + y: self.y + n, + } + } +} + +impl Index for Point { + type Output = Option + fn index(self, _ i: usize) -> Option { + match i { + 0 => Some(self.x) + 1 => Some(self.y) + _ => None + } + } +} + +fn f(a: Point, b: Point) { + let c = a + b + let c2 = Add::add(a, b) + // let c3 = Add::add(a, 100) TODO: fix `type annotation is needed` + let d = c + as_i32(100) + let x = d[0] +} + +fn as_i32(_ x: i32) -> i32 { x } diff --git a/crates/hir-analysis/test_files/ty_check/ops.snap b/crates/hir-analysis/test_files/ty_check/ops.snap new file mode 100644 index 0000000000..e97ce96911 --- /dev/null +++ b/crates/hir-analysis/test_files/ty_check/ops.snap @@ -0,0 +1,662 @@ +--- +source: crates/hir-analysis/tests/ty_check.rs +expression: res +input_file: test_files/ty_check/ops.fe +--- +note: + ┌─ ops.fe:9:24 + │ + 9 │ fn not(self) -> Ok { + │ ╭────────────────────────^ +10 │ │ match self { +11 │ │ Ok::No => Ok::Yes +12 │ │ Ok::Yes => Ok::No +13 │ │ } +14 │ │ } + │ ╰─────^ Ok + +note: + ┌─ ops.fe:10:9 + │ +10 │ ╭ match self { +11 │ │ Ok::No => Ok::Yes +12 │ │ Ok::Yes => Ok::No +13 │ │ } + │ ╰─────────^ Ok + +note: + ┌─ ops.fe:10:15 + │ +10 │ match self { + │ ^^^^ Ok + +note: + ┌─ ops.fe:11:13 + │ +11 │ Ok::No => Ok::Yes + │ ^^^^^^ Ok + +note: + ┌─ ops.fe:11:23 + │ +11 │ Ok::No => Ok::Yes + │ ^^^^^^^ Ok + +note: + ┌─ ops.fe:12:13 + │ +12 │ Ok::Yes => Ok::No + │ ^^^^^^^ Ok + +note: + ┌─ ops.fe:12:24 + │ +12 │ Ok::Yes => Ok::No + │ ^^^^^^ Ok + +note: + ┌─ ops.fe:17:23 + │ +17 │ fn flip(ok: Ok) -> Ok { + │ ╭───────────────────────^ +18 │ │ !ok +19 │ │ } + │ ╰─^ Ok + +note: + ┌─ ops.fe:18:5 + │ +18 │ !ok + │ ^^^ Ok + +note: + ┌─ ops.fe:18:6 + │ +18 │ !ok + │ ^^ Ok + +note: + ┌─ ops.fe:22:38 + │ +22 │ fn eq(self, _ other: Ok) -> bool { + │ ╭──────────────────────────────────────^ +23 │ │ match (self, other) { +24 │ │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true +25 │ │ _ => false +26 │ │ } +27 │ │ } + │ ╰─────^ bool + +note: + ┌─ ops.fe:23:9 + │ +23 │ ╭ match (self, other) { +24 │ │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true +25 │ │ _ => false +26 │ │ } + │ ╰──────────^ bool + +note: + ┌─ ops.fe:23:15 + │ +23 │ match (self, other) { + │ ^^^^^^^^^^^^^ (Ok, Ok) + +note: + ┌─ ops.fe:23:16 + │ +23 │ match (self, other) { + │ ^^^^ Ok + +note: + ┌─ ops.fe:23:22 + │ +23 │ match (self, other) { + │ ^^^^^ Ok + +note: + ┌─ ops.fe:24:13 + │ +24 │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + │ ^^^^^^^^^^^^^^^^^^ (Ok, Ok) + +note: + ┌─ ops.fe:24:13 + │ +24 │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Ok, Ok) + +note: + ┌─ ops.fe:24:14 + │ +24 │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + │ ^^^^^^^ Ok + +note: + ┌─ ops.fe:24:23 + │ +24 │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + │ ^^^^^^^ Ok + +note: + ┌─ ops.fe:24:34 + │ +24 │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + │ ^^^^^^^^^^^^^^^^ (Ok, Ok) + +note: + ┌─ ops.fe:24:35 + │ +24 │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + │ ^^^^^^ Ok + +note: + ┌─ ops.fe:24:43 + │ +24 │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + │ ^^^^^^ Ok + +note: + ┌─ ops.fe:24:54 + │ +24 │ (Ok::Yes, Ok::Yes) | (Ok::No, Ok::No) => true + │ ^^^^ bool + +note: + ┌─ ops.fe:25:13 + │ +25 │ _ => false + │ ^ (Ok, Ok) + +note: + ┌─ ops.fe:25:18 + │ +25 │ _ => false + │ ^^^^^ bool + +note: + ┌─ ops.fe:28:38 + │ +28 │ fn ne(self, _ other: Ok) -> bool { + │ ╭──────────────────────────────────────^ +29 │ │ !self.eq(other) +30 │ │ } + │ ╰─────^ bool + +note: + ┌─ ops.fe:29:9 + │ +29 │ !self.eq(other) + │ ^^^^^^^^^^^^^^^ bool + +note: + ┌─ ops.fe:29:10 + │ +29 │ !self.eq(other) + │ ^^^^ Ok + +note: + ┌─ ops.fe:29:10 + │ +29 │ !self.eq(other) + │ ^^^^^^^^^^^^^^ bool + +note: + ┌─ ops.fe:29:18 + │ +29 │ !self.eq(other) + │ ^^^^^ Ok + +note: + ┌─ ops.fe:34:42 + │ +34 │ fn add_assign(mut self, _ other: Ok) { + │ ╭──────────────────────────────────────────^ +35 │ │ if other == Ok::Yes { +36 │ │ self = Ok::Yes +37 │ │ } +38 │ │ } + │ ╰─────^ () + +note: + ┌─ ops.fe:35:9 + │ +35 │ ╭ if other == Ok::Yes { +36 │ │ self = Ok::Yes +37 │ │ } + │ ╰─────────^ () + +note: + ┌─ ops.fe:35:12 + │ +35 │ if other == Ok::Yes { + │ ^^^^^ Ok + +note: + ┌─ ops.fe:35:12 + │ +35 │ if other == Ok::Yes { + │ ^^^^^^^^^^^^^^^^ bool + +note: + ┌─ ops.fe:35:21 + │ +35 │ if other == Ok::Yes { + │ ^^^^^^^ Ok + +note: + ┌─ ops.fe:35:29 + │ +35 │ if other == Ok::Yes { + │ ╭─────────────────────────────^ +36 │ │ self = Ok::Yes +37 │ │ } + │ ╰─────────^ () + +note: + ┌─ ops.fe:36:13 + │ +36 │ self = Ok::Yes + │ ^^^^ Ok + +note: + ┌─ ops.fe:36:13 + │ +36 │ self = Ok::Yes + │ ^^^^^^^^^^^^^^ () + +note: + ┌─ ops.fe:36:20 + │ +36 │ self = Ok::Yes + │ ^^^^^^^ Ok + +note: + ┌─ ops.fe:47:39 + │ +47 │ fn add(self, _ p: Point) -> Point { + │ ╭───────────────────────────────────────^ +48 │ │ Point { +49 │ │ x: self.x + p.x, +50 │ │ y: self.y + p.y, +51 │ │ } +52 │ │ } + │ ╰─────^ Point + +note: + ┌─ ops.fe:48:9 + │ +48 │ ╭ Point { +49 │ │ x: self.x + p.x, +50 │ │ y: self.y + p.y, +51 │ │ } + │ ╰─────────^ Point + +note: + ┌─ ops.fe:49:16 + │ +49 │ x: self.x + p.x, + │ ^^^^ Point + +note: + ┌─ ops.fe:49:16 + │ +49 │ x: self.x + p.x, + │ ^^^^^^ i32 + +note: + ┌─ ops.fe:49:16 + │ +49 │ x: self.x + p.x, + │ ^^^^^^^^^^^^ i32 + +note: + ┌─ ops.fe:49:25 + │ +49 │ x: self.x + p.x, + │ ^ Point + +note: + ┌─ ops.fe:49:25 + │ +49 │ x: self.x + p.x, + │ ^^^ i32 + +note: + ┌─ ops.fe:50:16 + │ +50 │ y: self.y + p.y, + │ ^^^^ Point + +note: + ┌─ ops.fe:50:16 + │ +50 │ y: self.y + p.y, + │ ^^^^^^ i32 + +note: + ┌─ ops.fe:50:16 + │ +50 │ y: self.y + p.y, + │ ^^^^^^^^^^^^ i32 + +note: + ┌─ ops.fe:50:25 + │ +50 │ y: self.y + p.y, + │ ^ Point + +note: + ┌─ ops.fe:50:25 + │ +50 │ y: self.y + p.y, + │ ^^^ i32 + +note: + ┌─ ops.fe:56:37 + │ +56 │ fn add(self, _ n: i32) -> Point { + │ ╭─────────────────────────────────────^ +57 │ │ Point { +58 │ │ x: self.x + n, +59 │ │ y: self.y + n, +60 │ │ } +61 │ │ } + │ ╰─────^ Point + +note: + ┌─ ops.fe:57:9 + │ +57 │ ╭ Point { +58 │ │ x: self.x + n, +59 │ │ y: self.y + n, +60 │ │ } + │ ╰─────────^ Point + +note: + ┌─ ops.fe:58:16 + │ +58 │ x: self.x + n, + │ ^^^^ Point + +note: + ┌─ ops.fe:58:16 + │ +58 │ x: self.x + n, + │ ^^^^^^ i32 + +note: + ┌─ ops.fe:58:16 + │ +58 │ x: self.x + n, + │ ^^^^^^^^^^ i32 + +note: + ┌─ ops.fe:58:25 + │ +58 │ x: self.x + n, + │ ^ i32 + +note: + ┌─ ops.fe:59:16 + │ +59 │ y: self.y + n, + │ ^^^^ Point + +note: + ┌─ ops.fe:59:16 + │ +59 │ y: self.y + n, + │ ^^^^^^ i32 + +note: + ┌─ ops.fe:59:16 + │ +59 │ y: self.y + n, + │ ^^^^^^^^^^ i32 + +note: + ┌─ ops.fe:59:25 + │ +59 │ y: self.y + n, + │ ^ i32 + +note: + ┌─ ops.fe:66:47 + │ +66 │ fn index(self, _ i: usize) -> Option { + │ ╭───────────────────────────────────────────────^ +67 │ │ match i { +68 │ │ 0 => Some(self.x) +69 │ │ 1 => Some(self.y) +70 │ │ _ => None +71 │ │ } +72 │ │ } + │ ╰─────^ Option + +note: + ┌─ ops.fe:67:9 + │ +67 │ ╭ match i { +68 │ │ 0 => Some(self.x) +69 │ │ 1 => Some(self.y) +70 │ │ _ => None +71 │ │ } + │ ╰─────────^ Option + +note: + ┌─ ops.fe:67:15 + │ +67 │ match i { + │ ^ usize + +note: + ┌─ ops.fe:68:13 + │ +68 │ 0 => Some(self.x) + │ ^ usize + +note: + ┌─ ops.fe:68:18 + │ +68 │ 0 => Some(self.x) + │ ^^^^ fn Some + +note: + ┌─ ops.fe:68:18 + │ +68 │ 0 => Some(self.x) + │ ^^^^^^^^^^^^ Option + +note: + ┌─ ops.fe:68:23 + │ +68 │ 0 => Some(self.x) + │ ^^^^ Point + +note: + ┌─ ops.fe:68:23 + │ +68 │ 0 => Some(self.x) + │ ^^^^^^ i32 + +note: + ┌─ ops.fe:69:13 + │ +69 │ 1 => Some(self.y) + │ ^ usize + +note: + ┌─ ops.fe:69:18 + │ +69 │ 1 => Some(self.y) + │ ^^^^ fn Some + +note: + ┌─ ops.fe:69:18 + │ +69 │ 1 => Some(self.y) + │ ^^^^^^^^^^^^ Option + +note: + ┌─ ops.fe:69:23 + │ +69 │ 1 => Some(self.y) + │ ^^^^ Point + +note: + ┌─ ops.fe:69:23 + │ +69 │ 1 => Some(self.y) + │ ^^^^^^ i32 + +note: + ┌─ ops.fe:70:13 + │ +70 │ _ => None + │ ^ usize + +note: + ┌─ ops.fe:70:18 + │ +70 │ _ => None + │ ^^^^ Option + +note: + ┌─ ops.fe:75:26 + │ +75 │ fn f(a: Point, b: Point) { + │ ╭──────────────────────────^ +76 │ │ let c = a + b +77 │ │ let c2 = Add::add(a, b) +78 │ │ // let c3 = Add::add(a, 100) TODO: fix `type annotation is needed` +79 │ │ let d = c + as_i32(100) +80 │ │ let x = d[0] +81 │ │ } + │ ╰─^ () + +note: + ┌─ ops.fe:76:9 + │ +76 │ let c = a + b + │ ^ Point + +note: + ┌─ ops.fe:76:13 + │ +76 │ let c = a + b + │ ^ Point + +note: + ┌─ ops.fe:76:13 + │ +76 │ let c = a + b + │ ^^^^^ Point + +note: + ┌─ ops.fe:76:17 + │ +76 │ let c = a + b + │ ^ Point + +note: + ┌─ ops.fe:77:9 + │ +77 │ let c2 = Add::add(a, b) + │ ^^ Point + +note: + ┌─ ops.fe:77:14 + │ +77 │ let c2 = Add::add(a, b) + │ ^^^^^^^^ fn add + +note: + ┌─ ops.fe:77:14 + │ +77 │ let c2 = Add::add(a, b) + │ ^^^^^^^^^^^^^^ Point + +note: + ┌─ ops.fe:77:23 + │ +77 │ let c2 = Add::add(a, b) + │ ^ Point + +note: + ┌─ ops.fe:77:26 + │ +77 │ let c2 = Add::add(a, b) + │ ^ Point + +note: + ┌─ ops.fe:79:9 + │ +79 │ let d = c + as_i32(100) + │ ^ Point + +note: + ┌─ ops.fe:79:13 + │ +79 │ let d = c + as_i32(100) + │ ^ Point + +note: + ┌─ ops.fe:79:13 + │ +79 │ let d = c + as_i32(100) + │ ^^^^^^^^^^^^^^^ Point + +note: + ┌─ ops.fe:79:17 + │ +79 │ let d = c + as_i32(100) + │ ^^^^^^ fn as_i32 + +note: + ┌─ ops.fe:79:17 + │ +79 │ let d = c + as_i32(100) + │ ^^^^^^^^^^^ i32 + +note: + ┌─ ops.fe:79:24 + │ +79 │ let d = c + as_i32(100) + │ ^^^ i32 + +note: + ┌─ ops.fe:80:9 + │ +80 │ let x = d[0] + │ ^ Option + +note: + ┌─ ops.fe:80:13 + │ +80 │ let x = d[0] + │ ^ Point + +note: + ┌─ ops.fe:80:13 + │ +80 │ let x = d[0] + │ ^^^^ Option + +note: + ┌─ ops.fe:80:15 + │ +80 │ let x = d[0] + │ ^ usize + +note: + ┌─ ops.fe:83:28 + │ +83 │ fn as_i32(_ x: i32) -> i32 { x } + │ ^^^^^ i32 + +note: + ┌─ ops.fe:83:30 + │ +83 │ fn as_i32(_ x: i32) -> i32 { x } + │ ^ i32 diff --git a/crates/hir-analysis/test_files/ty_check/ops_num.fe b/crates/hir-analysis/test_files/ty_check/ops_num.fe new file mode 100644 index 0000000000..294a8a6c10 --- /dev/null +++ b/crates/hir-analysis/test_files/ty_check/ops_num.fe @@ -0,0 +1,6 @@ +fn f() -> i32 { + let mut x = -1 + x += 10 + x = x - 1 + x +} diff --git a/crates/hir-analysis/test_files/ty_check/ops_num.snap b/crates/hir-analysis/test_files/ty_check/ops_num.snap new file mode 100644 index 0000000000..a0d74f5b54 --- /dev/null +++ b/crates/hir-analysis/test_files/ty_check/ops_num.snap @@ -0,0 +1,88 @@ +--- +source: crates/hir-analysis/tests/ty_check.rs +expression: res +input_file: test_files/ty_check/ops_num.fe +--- +note: + ┌─ ops_num.fe:1:15 + │ +1 │ fn f() -> i32 { + │ ╭───────────────^ +2 │ │ let mut x = -1 +3 │ │ x += 10 +4 │ │ x = x - 1 +5 │ │ x +6 │ │ } + │ ╰─^ i32 + +note: + ┌─ ops_num.fe:2:9 + │ +2 │ let mut x = -1 + │ ^^^^^ i32 + +note: + ┌─ ops_num.fe:2:17 + │ +2 │ let mut x = -1 + │ ^^ i32 + +note: + ┌─ ops_num.fe:2:18 + │ +2 │ let mut x = -1 + │ ^ i32 + +note: + ┌─ ops_num.fe:3:5 + │ +3 │ x += 10 + │ ^ i32 + +note: + ┌─ ops_num.fe:3:5 + │ +3 │ x += 10 + │ ^^^^^^^ () + +note: + ┌─ ops_num.fe:3:10 + │ +3 │ x += 10 + │ ^^ i32 + +note: + ┌─ ops_num.fe:4:5 + │ +4 │ x = x - 1 + │ ^ i32 + +note: + ┌─ ops_num.fe:4:5 + │ +4 │ x = x - 1 + │ ^^^^^^^^^ () + +note: + ┌─ ops_num.fe:4:9 + │ +4 │ x = x - 1 + │ ^ i32 + +note: + ┌─ ops_num.fe:4:9 + │ +4 │ x = x - 1 + │ ^^^^^ i32 + +note: + ┌─ ops_num.fe:4:13 + │ +4 │ x = x - 1 + │ ^ i32 + +note: + ┌─ ops_num.fe:5:5 + │ +5 │ x + │ ^ i32 diff --git a/crates/hir-analysis/test_files/ty_check/trait_projection.snap b/crates/hir-analysis/test_files/ty_check/trait_projection.snap index ce12c2efdc..b67669a334 100644 --- a/crates/hir-analysis/test_files/ty_check/trait_projection.snap +++ b/crates/hir-analysis/test_files/ty_check/trait_projection.snap @@ -77,7 +77,7 @@ note: 51 │ ╭ { 52 │ │ x.into_iter().next() 53 │ │ } - │ ╰─^ T::Item + │ ╰─^ T::IntoIter::Item note: ┌─ trait_projection.fe:52:5 @@ -95,4 +95,4 @@ note: ┌─ trait_projection.fe:52:5 │ 52 │ x.into_iter().next() - │ ^^^^^^^^^^^^^^^^^^^^ T::Item + │ ^^^^^^^^^^^^^^^^^^^^ T::IntoIter::Item diff --git a/crates/hir-analysis/tests/corelib.rs b/crates/hir-analysis/tests/corelib.rs index 83ba020285..fc089d5551 100644 --- a/crates/hir-analysis/tests/corelib.rs +++ b/crates/hir-analysis/tests/corelib.rs @@ -1,14 +1,8 @@ mod test_db; -use camino::Utf8Path; use common::core::HasBuiltinCore; - -use common::InputDb; -use dir_test::{dir_test, Fixture}; use driver::DriverDataBase; -use url::Url; - #[cfg(target_arch = "wasm32")] use test_utils::url_utils::UrlExt; @@ -21,30 +15,8 @@ fn analyze_corelib() { if !(core_diags.is_empty()) { core_diags.emit(&db); panic!( - "expected no diagnostics, but got:\n{:?}", + "expected no diagnostics, but got:\n{}", core_diags.format_diags(&db) ); } } - -#[dir_test( - dir: "$CARGO_MANIFEST_DIR/test_files/corelib", - glob: "*.fe" -)] -fn corelib_standalone(fixture: Fixture<&str>) { - let mut db = DriverDataBase::default(); - let path = Utf8Path::new(fixture.path()).canonicalize().unwrap(); - let url = Url::from_file_path(path).unwrap(); - db.workspace() - .touch(&mut db, url.clone(), Some(fixture.content().to_string())); - - let local_diags = db.run_on_ingot( - db.workspace() - .containing_ingot(&db, url) - .expect("Failed to find containing ingot"), - ); - if !local_diags.is_empty() { - local_diags.emit(&db); - panic!("expected no diagnostics"); - } -} diff --git a/crates/hir/src/hir_def/expr.rs b/crates/hir/src/hir_def/expr.rs index c2bb5d3978..ef12d2a14a 100644 --- a/crates/hir/src/hir_def/expr.rs +++ b/crates/hir/src/hir_def/expr.rs @@ -8,10 +8,8 @@ pub enum Expr<'db> { Lit(LitKind<'db>), Block(Vec), /// The first `ExprId` is the lhs, the second is the rhs. - /// - /// and a `BinOp`. - Bin(ExprId, ExprId, Partial), - Un(ExprId, Partial), + Bin(ExprId, ExprId, BinOp), + Un(ExprId, UnOp), /// (callee, call args) Call(ExprId, Vec>), /// (receiver, method_name, generic args, call args) @@ -27,8 +25,6 @@ pub enum Expr<'db> { RecordInit(Partial>, Vec>), Field(ExprId, Partial>), Tuple(Vec), - /// The first `ExprId` is the indexed expression, the second is the index. - Index(ExprId, ExprId), Array(Vec), /// The size of the rep should be the body instead of expression, because it @@ -85,6 +81,8 @@ pub enum BinOp { Arith(ArithBinOp), Comp(CompBinOp), Logical(LogicalBinOp), + /// `[]` + Index, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/hir/src/hir_def/ident.rs b/crates/hir/src/hir_def/ident.rs index ea7279c3f3..955d546603 100644 --- a/crates/hir/src/hir_def/ident.rs +++ b/crates/hir/src/hir_def/ident.rs @@ -27,6 +27,7 @@ macro_rules! define_keywords { define_keywords! { (ingot, "ingot"), + (core, "core"), (super, "super"), (self, "self"), (self_ty, "Self"), diff --git a/crates/hir/src/hir_def/mod.rs b/crates/hir/src/hir_def/mod.rs index da6bbaaaba..8ab564d488 100644 --- a/crates/hir/src/hir_def/mod.rs +++ b/crates/hir/src/hir_def/mod.rs @@ -216,6 +216,18 @@ impl Partial { } } +impl PartialEq for Partial +where + T: PartialEq, +{ + fn eq(&self, other: &T) -> bool { + match self { + Self::Present(a) => a == other, + _ => false, + } + } +} + impl Default for Partial { fn default() -> Self { Self::Absent diff --git a/crates/hir/src/hir_def/path.rs b/crates/hir/src/hir_def/path.rs index 9b5411b493..199d5ec9de 100644 --- a/crates/hir/src/hir_def/path.rs +++ b/crates/hir/src/hir_def/path.rs @@ -112,26 +112,54 @@ impl<'db> PathId<'db> { } } - pub fn push( + pub fn replace_root( self, + from: IdentId<'db>, + to: IdentId<'db>, db: &'db dyn HirDb, - ident: Partial>, - generic_args: GenericArgListId<'db>, - ) -> Self { - Self::new( + ) -> PathId<'db> { + match self.parent(db) { + Some(parent) => parent.replace_root(from, to, db).push(db, self.kind(db)), + None => { + let kind = match self.kind(db) { + PathKind::Ident { + ident, + generic_args, + } if ident == from => PathKind::Ident { + ident: Partial::Present(to), + generic_args, + }, + kind => kind, + }; + PathId::new(db, kind, None) + } + } + } + + pub fn is_core_lib_path(self, db: &'db dyn HirDb) -> bool { + match self.parent(db) { + Some(parent) => parent.is_core_lib_path(db), + None => self + .as_ident(db) + .map(|id| id.data(db) == "core") + .unwrap_or_default(), + } + } + + pub fn push(self, db: &'db dyn HirDb, kind: PathKind<'db>) -> Self { + Self::new(db, kind, Some(self)) + } + + pub fn push_ident(self, db: &'db dyn HirDb, ident: IdentId<'db>) -> Self { + self.push( db, PathKind::Ident { - ident, - generic_args, + ident: Partial::Present(ident), + generic_args: GenericArgListId::none(db), }, - Some(self), ) } - pub fn push_ident(self, db: &'db dyn HirDb, ident: IdentId<'db>) -> Self { - self.push(db, Partial::Present(ident), GenericArgListId::none(db)) - } - pub fn ident(self, db: &'db dyn HirDb) -> Partial> { match self.kind(db) { PathKind::Ident { ident, .. } => ident, diff --git a/crates/hir/src/lower/expr.rs b/crates/hir/src/lower/expr.rs index 8df114f931..f6f8b2cdc1 100644 --- a/crates/hir/src/lower/expr.rs +++ b/crates/hir/src/lower/expr.rs @@ -41,13 +41,15 @@ impl<'db> Expr<'db> { ast::ExprKind::Bin(bin) => { let lhs = Self::push_to_body_opt(ctxt, bin.lhs()); let rhs = Self::push_to_body_opt(ctxt, bin.rhs()); - let op = bin.op().map(BinOp::lower_ast).into(); + let op = bin.op().expect("parser guarantees op presence"); + let op = BinOp::lower_ast(op); Self::Bin(lhs, rhs, op) } ast::ExprKind::Un(un) => { let expr = Self::push_to_body_opt(ctxt, un.expr()); - let op = un.op().map(UnOp::lower_ast).into(); + let op = un.op().expect("parser guarantees op presence"); + let op = UnOp::lower_ast(op); Self::Un(expr, op) } @@ -115,7 +117,7 @@ impl<'db> Expr<'db> { ast::ExprKind::Index(index) => { let indexed = Self::push_to_body_opt(ctxt, index.expr()); let index = Self::push_to_body_opt(ctxt, index.index()); - Self::Index(indexed, index) + Self::Bin(indexed, index, BinOp::Index) } ast::ExprKind::Tuple(tup) => { @@ -182,9 +184,9 @@ impl<'db> Expr<'db> { ast::ExprKind::AugAssign(aug_assign) => { let lhs = Self::push_to_body_opt(ctxt, aug_assign.lhs_expr()); let rhs = Self::push_to_body_opt(ctxt, aug_assign.rhs_expr()); - let binop = aug_assign.op().map(ArithBinOp::lower_ast).unwrap(); - - Self::AugAssign(lhs, rhs, binop) + let op = aug_assign.op().expect("parser guarantees op presence"); + let op = ArithBinOp::lower_ast(op); + Self::AugAssign(lhs, rhs, op) } }; diff --git a/crates/hir/src/visitor.rs b/crates/hir/src/visitor.rs index 0539bde2e7..5c358b0a39 100644 --- a/crates/hir/src/visitor.rs +++ b/crates/hir/src/visitor.rs @@ -1107,11 +1107,6 @@ pub fn walk_expr<'db, V>( } } - Expr::Index(lhs_id, rhs_id) => { - visit_node_in_body!(visitor, ctxt, lhs_id, expr); - visit_node_in_body!(visitor, ctxt, rhs_id, expr); - } - Expr::Array(elems) => { for elem_id in elems { visit_node_in_body!(visitor, ctxt, elem_id, expr); diff --git a/crates/parser/src/ast/item.rs b/crates/parser/src/ast/item.rs index 7a551931d0..b4fb5852c7 100644 --- a/crates/parser/src/ast/item.rs +++ b/crates/parser/src/ast/item.rs @@ -447,7 +447,7 @@ ast_node! { ast_node! { pub struct ImplItemList, SK::ImplItemList, - IntoIterator, // xxx ImplTraitItem + IntoIterator, // TODO: ImplTraitItem } ast_node! { diff --git a/crates/uitest/fixtures/ty_check/ambiguous_associated_type_unify.fe b/crates/uitest/fixtures/ty_check/ambiguous_associated_type_unify.fe new file mode 100644 index 0000000000..592294a71c --- /dev/null +++ b/crates/uitest/fixtures/ty_check/ambiguous_associated_type_unify.fe @@ -0,0 +1,67 @@ +trait Producer { + type Output + fn produce(self) -> Self::Output +} + +trait Transformer { + type Output + fn transform(self) -> Self::Output +} + +struct Dual {} + +// Dual implements both traits with different Output types +impl Producer for Dual { + type Output = i32 + fn produce(self) -> i32 { 42 } +} + +impl Transformer for Dual { + type Output = bool + fn transform(self) -> bool { true } +} + +fn use_producer(_ t: T) -> T::Output +where T: Producer +{ + t.produce() +} + +fn use_transformer(_ t: T) -> T::Output +where T: Transformer +{ + t.transform() +} + +fn both_traits(_ t: T, _ t2: T) +where T: Producer + Transformer +{ + let x: T::Output = t.produce() + let y: T::Output = t2.transform() + + let z: ::Output = t.produce() +} + +// Test with a generic that tries to unify outputs +fn try_unify(_ t: T) -> T::Output +where T: Producer + Transformer +{ + // This is ambiguous - which trait's Output are we returning? + // With Dual, Producer::Output = i32 but Transformer::Output = bool + if true { + t.produce() // Returns Producer::Output (i32 for Dual) + } else { + t.transform() // Returns Transformer::Output (bool for Dual) + // These have different types but same associated type name! + } +} + +fn main() { + let d = Dual {} + + let a: i32 = use_producer(d) + let b: bool = use_transformer(d) + + both_traits(d, d) + let result = try_unify(d) +} diff --git a/crates/uitest/fixtures/ty_check/ambiguous_associated_type_unify.snap b/crates/uitest/fixtures/ty_check/ambiguous_associated_type_unify.snap new file mode 100644 index 0000000000..32e8fd29f7 --- /dev/null +++ b/crates/uitest/fixtures/ty_check/ambiguous_associated_type_unify.snap @@ -0,0 +1,52 @@ +--- +source: crates/uitest/tests/ty_check.rs +expression: diags +input_file: fixtures/ty_check/ambiguous_associated_type_unify.fe +--- +error[2-0009]: ambiguous associated type `Output` + ┌─ ambiguous_associated_type_unify.fe:39:15 + │ + 1 │ trait Producer { + │ -------- candidate: `Producer` + · + 6 │ trait Transformer { + │ ----------- candidate: `Transformer` + · +39 │ let x: T::Output = t.produce() + │ ^^^^^^ associated type `Output` is ambiguous + │ + = specify the trait explicitly: `::Output` + +error[2-0009]: ambiguous associated type `Output` + ┌─ ambiguous_associated_type_unify.fe:40:15 + │ + 1 │ trait Producer { + │ -------- candidate: `Producer` + · + 6 │ trait Transformer { + │ ----------- candidate: `Transformer` + · +40 │ let y: T::Output = t2.transform() + │ ^^^^^^ associated type `Output` is ambiguous + │ + = specify the trait explicitly: `::Output` + +error[2-0009]: ambiguous associated type `Output` + ┌─ ambiguous_associated_type_unify.fe:46:31 + │ + 1 │ trait Producer { + │ -------- candidate: `Producer` + · + 6 │ trait Transformer { + │ ----------- candidate: `Transformer` + · +46 │ fn try_unify(_ t: T) -> T::Output + │ ^^^^^^ associated type `Output` is ambiguous + │ + = specify the trait explicitly: `::Output` + +error[8-0000]: type mismatch + ┌─ ambiguous_associated_type_unify.fe:54:9 + │ +54 │ t.transform() // Returns Transformer::Output (bool for Dual) + │ ^^^^^^^^^^^^^ expected `T::Output`, but `T::Output` is given diff --git a/crates/uitest/fixtures/ty_check/aug_assign.snap b/crates/uitest/fixtures/ty_check/aug_assign.snap index ba0633b77c..d6e987b4ce 100644 --- a/crates/uitest/fixtures/ty_check/aug_assign.snap +++ b/crates/uitest/fixtures/ty_check/aug_assign.snap @@ -3,14 +3,22 @@ source: crates/uitest/tests/ty_check.rs expression: diags input_file: fixtures/ty_check/aug_assign.fe --- -error[8-0016]: `std::ops::SubAssign` trait is not implemented +error[8-0016]: `core::ops::SubAssign` trait is not implemented ┌─ aug_assign.fe:6:5 │ 6 │ f -= f │ ^^^^^^ │ │ │ `-=` can't be applied to `Foo` - │ Try implementing `std::ops::SubAssign` for `Foo` + │ Try implementing `core::ops::SubAssign` for `Foo` + +error[8-0018]: left-hand side of assignment is immutable + ┌─ aug_assign.fe:6:5 + │ +5 │ fn foo(f: Foo) { + │ - try changing to `mut f` +6 │ f -= f + │ ^ immutable assignment error[8-0018]: left-hand side of assignment is immutable ┌─ aug_assign.fe:7:5 diff --git a/crates/uitest/fixtures/ty_check/binary.snap b/crates/uitest/fixtures/ty_check/binary.snap index 77aecc89ab..afeaea2ea2 100644 --- a/crates/uitest/fixtures/ty_check/binary.snap +++ b/crates/uitest/fixtures/ty_check/binary.snap @@ -3,38 +3,47 @@ source: crates/uitest/tests/ty_check.rs expression: diags input_file: fixtures/ty_check/binary.fe --- -error[8-0016]: `std::ops::Add` trait is not implemented +error[8-0000]: type mismatch + ┌─ binary.fe:6:6 + │ +6 │ (f && f) || f + │ ^ expected `bool`, but `Foo` is given + +error[8-0000]: type mismatch + ┌─ binary.fe:6:11 + │ +6 │ (f && f) || f + │ ^ expected `bool`, but `Foo` is given + +error[8-0000]: type mismatch + ┌─ binary.fe:6:17 + │ +6 │ (f && f) || f + │ ^ expected `bool`, but `Foo` is given + +error[8-0016]: `core::ops::Add` trait is not implemented ┌─ binary.fe:4:5 │ 4 │ f + f │ ^^^^^ │ │ │ `+` can't be applied to `Foo` - │ Try implementing `std::ops::Add` for `Foo` - -error[8-0016]: `std::ops::And` trait is not implemented - ┌─ binary.fe:6:6 - │ -6 │ (f && f) || f - │ ^^^^^^ - │ │ - │ `&&` can't be applied to `Foo` - │ Try implementing `std::ops::And` for `Foo` + │ Try implementing `core::ops::Add` for `Foo` -error[8-0016]: `std::ops::Eq` trait is not implemented +error[8-0016]: `core::ops::Eq` trait is not implemented ┌─ binary.fe:7:5 │ 7 │ f == f │ ^^^^^^ │ │ │ `==` can't be applied to `Foo` - │ Try implementing `std::ops::Eq` for `Foo` + │ Try implementing `core::ops::Eq` for `Foo` -error[8-0016]: `std::ops::Ord` trait is not implemented +error[8-0016]: `core::ops::Ord` trait is not implemented ┌─ binary.fe:8:5 │ 8 │ f < f │ ^^^^^ │ │ │ `<` can't be applied to `Foo` - │ Try implementing `std::ops::Ord` for `Foo` + │ Try implementing `core::ops::Ord` for `Foo` diff --git a/crates/uitest/fixtures/ty_check/for_.snap b/crates/uitest/fixtures/ty_check/for_.snap index e5441d3f52..75f4493974 100644 --- a/crates/uitest/fixtures/ty_check/for_.snap +++ b/crates/uitest/fixtures/ty_check/for_.snap @@ -1,7 +1,7 @@ --- source: crates/uitest/tests/ty_check.rs expression: diags -input_file: crates/uitest/fixtures/ty_check/for_.fe +input_file: fixtures/ty_check/for_.fe --- error[8-0000]: type mismatch ┌─ for_.fe:16:9 @@ -26,5 +26,3 @@ error[8-0020]: `Iterator` needs to be implemented for Foo │ │ │ `Iterator` needs to be implemented for `Foo` │ consider implementing `Iterator` for `Foo` - - diff --git a/crates/uitest/fixtures/ty_check/generic_arg_path_resolution_fail.fe b/crates/uitest/fixtures/ty_check/generic_arg_path_resolution_fail.fe index be948bb1a0..a13ec7ca34 100644 --- a/crates/uitest/fixtures/ty_check/generic_arg_path_resolution_fail.fe +++ b/crates/uitest/fixtures/ty_check/generic_arg_path_resolution_fail.fe @@ -36,7 +36,6 @@ struct S2 { // Case 4: Associated type on concrete type that doesn't implement the trait struct Concrete {} -// xxx this shouldn't be a conflicting trait impl! impl Tr1 for S1 { type Foo = Concrete::Bar // Error: Concrete doesn't have associated type Bar diff --git a/crates/uitest/fixtures/ty_check/generic_arg_path_resolution_fail.snap b/crates/uitest/fixtures/ty_check/generic_arg_path_resolution_fail.snap index 76a786c807..09dc7da569 100644 --- a/crates/uitest/fixtures/ty_check/generic_arg_path_resolution_fail.snap +++ b/crates/uitest/fixtures/ty_check/generic_arg_path_resolution_fail.snap @@ -1,6 +1,5 @@ --- source: crates/uitest/tests/ty_check.rs -assertion_line: 20 expression: diags input_file: fixtures/ty_check/generic_arg_path_resolution_fail.fe --- @@ -17,13 +16,13 @@ error[2-0002]: `NonExistent` is not found │ ^^^^^^^^^^^ `NonExistent` is not found error[2-0002]: `Bar` is not found - ┌─ generic_arg_path_resolution_fail.fe:41:26 + ┌─ generic_arg_path_resolution_fail.fe:40:26 │ -41 │ type Foo = Concrete::Bar // Error: Concrete doesn't have associated type Bar +40 │ type Foo = Concrete::Bar // Error: Concrete doesn't have associated type Bar │ ^^^ `Bar` is not found error[2-0002]: `Missing` is not found - ┌─ generic_arg_path_resolution_fail.fe:54:26 + ┌─ generic_arg_path_resolution_fail.fe:53:26 │ -54 │ type Foo = T::Inner::Missing // Error: T::Inner doesn't have associated type Missing +53 │ type Foo = T::Inner::Missing // Error: T::Inner doesn't have associated type Missing │ ^^^^^^^ `Missing` is not found diff --git a/crates/uitest/fixtures/ty_check/index.fe b/crates/uitest/fixtures/ty_check/index.fe index 17963499d1..7667448d64 100644 --- a/crates/uitest/fixtures/ty_check/index.fe +++ b/crates/uitest/fixtures/ty_check/index.fe @@ -1,7 +1,22 @@ -struct Foo {} +struct Foo {} +struct Bar {} -pub fn foo(x: [i32; 10]) -> i32 { +impl core::ops::Index for Bar { + type Output = bool + + fn index(self, _ i: i32) -> bool { + if i % 2 == 0 { + true + } else { + false + } + } +} + +pub fn foo(x: [i32; 10]) -> bool { x[false] let f = Foo { } f[1] + let b = Bar { } + b[5] } diff --git a/crates/uitest/fixtures/ty_check/index.snap b/crates/uitest/fixtures/ty_check/index.snap index 0cf9e02ef3..4541a7d424 100644 --- a/crates/uitest/fixtures/ty_check/index.snap +++ b/crates/uitest/fixtures/ty_check/index.snap @@ -4,16 +4,16 @@ expression: diags input_file: fixtures/ty_check/index.fe --- error[8-0000]: type mismatch - ┌─ index.fe:4:7 - │ -4 │ x[false] - │ ^^^^^ expected `u256`, but `bool` is given + ┌─ index.fe:17:7 + │ +17 │ x[false] + │ ^^^^^ expected `u256`, but `bool` is given -error[8-0016]: `std::ops::Index` trait is not implemented - ┌─ index.fe:6:5 - │ -6 │ f[1] - │ ^^^^ - │ │ - │ `[]` can't be applied to `Foo` - │ Try implementing `std::ops::Index` for `Foo` +error[8-0016]: `core::ops::Index` trait is not implemented + ┌─ index.fe:19:5 + │ +19 │ f[1] + │ ^^^^ + │ │ + │ `[]` can't be applied to `Foo` + │ Try implementing `core::ops::Index` for `Foo` diff --git a/crates/uitest/fixtures/ty_check/method_bound/arg_bound.fe b/crates/uitest/fixtures/ty_check/method_bound/arg_bound.fe index ecf95b500e..4c1df3363d 100644 --- a/crates/uitest/fixtures/ty_check/method_bound/arg_bound.fe +++ b/crates/uitest/fixtures/ty_check/method_bound/arg_bound.fe @@ -4,7 +4,7 @@ extern { fn todo() -> ! } -trait Extract +trait Extract where Self: * -> * { fn extract(self: Self) -> T @@ -54,7 +54,7 @@ impl Clone for bool { fn foo() -> i32 { let s = S::new(false) extract(s) - + let opt = Some(1) extract(opt) -} \ No newline at end of file +} diff --git a/crates/uitest/fixtures/ty_check/method_selection/ambiguous_inherent_method.fe b/crates/uitest/fixtures/ty_check/method_selection/ambiguous_inherent_method.fe index de0a5e8c5f..3841a3e645 100644 --- a/crates/uitest/fixtures/ty_check/method_selection/ambiguous_inherent_method.fe +++ b/crates/uitest/fixtures/ty_check/method_selection/ambiguous_inherent_method.fe @@ -7,7 +7,7 @@ trait Default { fn default() -> Self } -impl Default for Foo +impl Default for Foo where T: Default { fn default() -> Self { @@ -33,4 +33,4 @@ impl Foo { fn bar() { let f = Foo::default() f.foo() -} \ No newline at end of file +} diff --git a/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_def.fe b/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_def.fe index 1535f7f4c9..4904b1a0b8 100644 --- a/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_def.fe +++ b/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_def.fe @@ -36,4 +36,4 @@ extern { fn run() { let f = Foo::new() let y = f.foo() -} \ No newline at end of file +} diff --git a/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_def.snap b/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_def.snap index bd6333f8e4..4f0e52c12c 100644 --- a/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_def.snap +++ b/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_def.snap @@ -21,3 +21,12 @@ error[8-0031]: type annotation is needed │ │ │ type annotation is needed │ consider giving `: Foo<_>` here + +error[8-0031]: type annotation is needed + ┌─ ambiguous_trait_def.fe:38:9 + │ +38 │ let y = f.foo() + │ ^ + │ │ + │ type annotation is needed + │ consider giving `: Type` here diff --git a/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_inst.snap b/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_inst.snap index 3130fc1a0f..49c32d5afd 100644 --- a/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_inst.snap +++ b/crates/uitest/fixtures/ty_check/method_selection/ambiguous_trait_inst.snap @@ -3,15 +3,15 @@ source: crates/uitest/tests/ty_check.rs expression: diags input_file: fixtures/ty_check/method_selection/ambiguous_trait_inst.fe --- -error[8-0027]: ambiguous trait implementation - ┌─ ambiguous_trait_inst.fe:23:13 +error[8-0026]: multiple trait candidates found + ┌─ ambiguous_trait_inst.fe:23:15 │ 23 │ let y = f.foo() - │ ^^^^^^^ - │ │ - │ multiple implementations are found - │ candidate: Trait - │ candidate: Trait + │ ^^^ + │ │ + │ `foo` is ambiguous + │ candidate: `Trait::foo` + │ candidate: `Trait::foo` error[8-0031]: type annotation is needed ┌─ ambiguous_trait_inst.fe:23:9 diff --git a/crates/uitest/fixtures/ty_check/unary.fe b/crates/uitest/fixtures/ty_check/unary.fe index 3b7524d49f..45d714d0ed 100644 --- a/crates/uitest/fixtures/ty_check/unary.fe +++ b/crates/uitest/fixtures/ty_check/unary.fe @@ -5,4 +5,4 @@ fn foo() { +f -f !f -} \ No newline at end of file +} diff --git a/crates/uitest/fixtures/ty_check/unary.snap b/crates/uitest/fixtures/ty_check/unary.snap index da984b0461..bb7930b0f9 100644 --- a/crates/uitest/fixtures/ty_check/unary.snap +++ b/crates/uitest/fixtures/ty_check/unary.snap @@ -3,29 +3,20 @@ source: crates/uitest/tests/ty_check.rs expression: diags input_file: fixtures/ty_check/unary.fe --- -error[8-0016]: `std::ops::UnaryPlus` trait is not implemented - ┌─ unary.fe:5:5 - │ -5 │ +f - │ ^^ - │ │ - │ `+` can't be applied to `Foo` - │ Try implementing `std::ops::UnaryPlus` for `Foo` - -error[8-0016]: `std::ops::Neg` trait is not implemented +error[8-0016]: `core::ops::Neg` trait is not implemented ┌─ unary.fe:6:5 │ 6 │ -f │ ^^ │ │ │ `-` can't be applied to `Foo` - │ Try implementing `std::ops::Neg` for `Foo` + │ Try implementing `core::ops::Neg` for `Foo` -error[8-0016]: `std::ops::Not` trait is not implemented +error[8-0016]: `core::ops::Not` trait is not implemented ┌─ unary.fe:7:5 │ 7 │ !f │ ^^ │ │ │ `!` can't be applied to `Foo` - │ Try implementing `std::ops::Not` for `Foo` + │ Try implementing `core::ops::Not` for `Foo` diff --git a/library/core/src/default.fe b/library/core/src/default.fe index 972cc8080e..9093eba86c 100644 --- a/library/core/src/default.fe +++ b/library/core/src/default.fe @@ -1,9 +1,3 @@ pub trait Default { fn default() -> Self } - -impl Default for usize { - fn default() -> Self { - 0 - } -} diff --git a/library/core/src/lib.fe b/library/core/src/lib.fe index 341c7405d8..2dd1081244 100644 --- a/library/core/src/lib.fe +++ b/library/core/src/lib.fe @@ -1,5 +1,6 @@ pub use option::Option pub use default::Default +pub use ops::* extern { pub fn panic() -> ! diff --git a/library/core/src/num.fe b/library/core/src/num.fe new file mode 100644 index 0000000000..a295b20744 --- /dev/null +++ b/library/core/src/num.fe @@ -0,0 +1,868 @@ +use super::ops::* +use super::default::Default + +// Extern intrinsics for u8 +extern { + fn __add_u8(_: u8, _: u8) -> u8 + fn __sub_u8(_: u8, _: u8) -> u8 + fn __mul_u8(_: u8, _: u8) -> u8 + fn __div_u8(_: u8, _: u8) -> u8 + fn __rem_u8(_: u8, _: u8) -> u8 + fn __pow_u8(_: u8, _: u8) -> u8 + fn __shl_u8(_: u8, _: u8) -> u8 + fn __shr_u8(_: u8, _: u8) -> u8 + fn __bitand_u8(_: u8, _: u8) -> u8 + fn __bitor_u8(_: u8, _: u8) -> u8 + fn __bitxor_u8(_: u8, _: u8) -> u8 + + fn __eq_u8(_: u8, _: u8) -> bool + fn __ne_u8(_: u8, _: u8) -> bool + fn __lt_u8(_: u8, _: u8) -> bool + fn __le_u8(_: u8, _: u8) -> bool + fn __gt_u8(_: u8, _: u8) -> bool + fn __ge_u8(_: u8, _: u8) -> bool + + fn __bitnot_u8(_: u8) -> u8 +} + +// Extern intrinsics for i8 +extern { + fn __add_i8(_: i8, _: i8) -> i8 + fn __sub_i8(_: i8, _: i8) -> i8 + fn __mul_i8(_: i8, _: i8) -> i8 + fn __div_i8(_: i8, _: i8) -> i8 + fn __rem_i8(_: i8, _: i8) -> i8 + fn __pow_i8(_: i8, _: i8) -> i8 + fn __shl_i8(_: i8, _: i8) -> i8 + fn __shr_i8(_: i8, _: i8) -> i8 + fn __bitand_i8(_: i8, _: i8) -> i8 + fn __bitor_i8(_: i8, _: i8) -> i8 + fn __bitxor_i8(_: i8, _: i8) -> i8 + + fn __eq_i8(_: i8, _: i8) -> bool + fn __ne_i8(_: i8, _: i8) -> bool + fn __lt_i8(_: i8, _: i8) -> bool + fn __le_i8(_: i8, _: i8) -> bool + fn __gt_i8(_: i8, _: i8) -> bool + fn __ge_i8(_: i8, _: i8) -> bool + + fn __neg_i8(_: i8) -> i8 + fn __bitnot_i8(_: i8) -> i8 +} + +// Extern intrinsics for i16 +extern { + fn __add_i16(_: i16, _: i16) -> i16 + fn __sub_i16(_: i16, _: i16) -> i16 + fn __mul_i16(_: i16, _: i16) -> i16 + fn __div_i16(_: i16, _: i16) -> i16 + fn __rem_i16(_: i16, _: i16) -> i16 + fn __pow_i16(_: i16, _: i16) -> i16 + fn __shl_i16(_: i16, _: i16) -> i16 + fn __shr_i16(_: i16, _: i16) -> i16 + fn __bitand_i16(_: i16, _: i16) -> i16 + fn __bitor_i16(_: i16, _: i16) -> i16 + fn __bitxor_i16(_: i16, _: i16) -> i16 + + fn __eq_i16(_: i16, _: i16) -> bool + fn __ne_i16(_: i16, _: i16) -> bool + fn __lt_i16(_: i16, _: i16) -> bool + fn __le_i16(_: i16, _: i16) -> bool + fn __gt_i16(_: i16, _: i16) -> bool + fn __ge_i16(_: i16, _: i16) -> bool + + fn __neg_i16(_: i16) -> i16 + fn __bitnot_i16(_: i16) -> i16 +} + +// Extern intrinsics for u16 +extern { + fn __add_u16(_: u16, _: u16) -> u16 + fn __sub_u16(_: u16, _: u16) -> u16 + fn __mul_u16(_: u16, _: u16) -> u16 + fn __div_u16(_: u16, _: u16) -> u16 + fn __rem_u16(_: u16, _: u16) -> u16 + fn __pow_u16(_: u16, _: u16) -> u16 + fn __shl_u16(_: u16, _: u16) -> u16 + fn __shr_u16(_: u16, _: u16) -> u16 + fn __bitand_u16(_: u16, _: u16) -> u16 + fn __bitor_u16(_: u16, _: u16) -> u16 + fn __bitxor_u16(_: u16, _: u16) -> u16 + + fn __eq_u16(_: u16, _: u16) -> bool + fn __ne_u16(_: u16, _: u16) -> bool + fn __lt_u16(_: u16, _: u16) -> bool + fn __le_u16(_: u16, _: u16) -> bool + fn __gt_u16(_: u16, _: u16) -> bool + fn __ge_u16(_: u16, _: u16) -> bool + + fn __bitnot_u16(_: u16) -> u16 +} + +// Extern intrinsics for i32 +extern { + fn __add_i32(_: i32, _: i32) -> i32 + fn __sub_i32(_: i32, _: i32) -> i32 + fn __mul_i32(_: i32, _: i32) -> i32 + fn __div_i32(_: i32, _: i32) -> i32 + fn __rem_i32(_: i32, _: i32) -> i32 + fn __pow_i32(_: i32, _: i32) -> i32 + fn __shl_i32(_: i32, _: i32) -> i32 + fn __shr_i32(_: i32, _: i32) -> i32 + fn __bitand_i32(_: i32, _: i32) -> i32 + fn __bitor_i32(_: i32, _: i32) -> i32 + fn __bitxor_i32(_: i32, _: i32) -> i32 + + fn __eq_i32(_: i32, _: i32) -> bool + fn __ne_i32(_: i32, _: i32) -> bool + fn __lt_i32(_: i32, _: i32) -> bool + fn __le_i32(_: i32, _: i32) -> bool + fn __gt_i32(_: i32, _: i32) -> bool + fn __ge_i32(_: i32, _: i32) -> bool + + fn __neg_i32(_: i32) -> i32 + fn __bitnot_i32(_: i32) -> i32 +} + +// Extern intrinsics for u32 +extern { + fn __add_u32(_: u32, _: u32) -> u32 + fn __sub_u32(_: u32, _: u32) -> u32 + fn __mul_u32(_: u32, _: u32) -> u32 + fn __div_u32(_: u32, _: u32) -> u32 + fn __rem_u32(_: u32, _: u32) -> u32 + fn __pow_u32(_: u32, _: u32) -> u32 + fn __shl_u32(_: u32, _: u32) -> u32 + fn __shr_u32(_: u32, _: u32) -> u32 + fn __bitand_u32(_: u32, _: u32) -> u32 + fn __bitor_u32(_: u32, _: u32) -> u32 + fn __bitxor_u32(_: u32, _: u32) -> u32 + + fn __eq_u32(_: u32, _: u32) -> bool + fn __ne_u32(_: u32, _: u32) -> bool + fn __lt_u32(_: u32, _: u32) -> bool + fn __le_u32(_: u32, _: u32) -> bool + fn __gt_u32(_: u32, _: u32) -> bool + fn __ge_u32(_: u32, _: u32) -> bool + + fn __bitnot_u32(_: u32) -> u32 +} + +// Extern intrinsics for i64 +extern { + fn __add_i64(_: i64, _: i64) -> i64 + fn __sub_i64(_: i64, _: i64) -> i64 + fn __mul_i64(_: i64, _: i64) -> i64 + fn __div_i64(_: i64, _: i64) -> i64 + fn __rem_i64(_: i64, _: i64) -> i64 + fn __pow_i64(_: i64, _: i64) -> i64 + fn __shl_i64(_: i64, _: i64) -> i64 + fn __shr_i64(_: i64, _: i64) -> i64 + fn __bitand_i64(_: i64, _: i64) -> i64 + fn __bitor_i64(_: i64, _: i64) -> i64 + fn __bitxor_i64(_: i64, _: i64) -> i64 + + fn __eq_i64(_: i64, _: i64) -> bool + fn __ne_i64(_: i64, _: i64) -> bool + fn __lt_i64(_: i64, _: i64) -> bool + fn __le_i64(_: i64, _: i64) -> bool + fn __gt_i64(_: i64, _: i64) -> bool + fn __ge_i64(_: i64, _: i64) -> bool + + fn __neg_i64(_: i64) -> i64 + fn __bitnot_i64(_: i64) -> i64 +} + +// Extern intrinsics for i128 +extern { + fn __add_i128(_: i128, _: i128) -> i128 + fn __sub_i128(_: i128, _: i128) -> i128 + fn __mul_i128(_: i128, _: i128) -> i128 + fn __div_i128(_: i128, _: i128) -> i128 + fn __rem_i128(_: i128, _: i128) -> i128 + fn __pow_i128(_: i128, _: i128) -> i128 + fn __shl_i128(_: i128, _: i128) -> i128 + fn __shr_i128(_: i128, _: i128) -> i128 + fn __bitand_i128(_: i128, _: i128) -> i128 + fn __bitor_i128(_: i128, _: i128) -> i128 + fn __bitxor_i128(_: i128, _: i128) -> i128 + + fn __eq_i128(_: i128, _: i128) -> bool + fn __ne_i128(_: i128, _: i128) -> bool + fn __lt_i128(_: i128, _: i128) -> bool + fn __le_i128(_: i128, _: i128) -> bool + fn __gt_i128(_: i128, _: i128) -> bool + fn __ge_i128(_: i128, _: i128) -> bool + + fn __neg_i128(_: i128) -> i128 + fn __bitnot_i128(_: i128) -> i128 +} + +// Extern intrinsics for u64 +extern { + fn __add_u64(_: u64, _: u64) -> u64 + fn __sub_u64(_: u64, _: u64) -> u64 + fn __mul_u64(_: u64, _: u64) -> u64 + fn __div_u64(_: u64, _: u64) -> u64 + fn __rem_u64(_: u64, _: u64) -> u64 + fn __pow_u64(_: u64, _: u64) -> u64 + fn __shl_u64(_: u64, _: u64) -> u64 + fn __shr_u64(_: u64, _: u64) -> u64 + fn __bitand_u64(_: u64, _: u64) -> u64 + fn __bitor_u64(_: u64, _: u64) -> u64 + fn __bitxor_u64(_: u64, _: u64) -> u64 + + fn __eq_u64(_: u64, _: u64) -> bool + fn __ne_u64(_: u64, _: u64) -> bool + fn __lt_u64(_: u64, _: u64) -> bool + fn __le_u64(_: u64, _: u64) -> bool + fn __gt_u64(_: u64, _: u64) -> bool + fn __ge_u64(_: u64, _: u64) -> bool + + fn __bitnot_u64(_: u64) -> u64 +} + +// Extern intrinsics for u128 +extern { + fn __add_u128(_: u128, _: u128) -> u128 + fn __sub_u128(_: u128, _: u128) -> u128 + fn __mul_u128(_: u128, _: u128) -> u128 + fn __div_u128(_: u128, _: u128) -> u128 + fn __rem_u128(_: u128, _: u128) -> u128 + fn __pow_u128(_: u128, _: u128) -> u128 + fn __shl_u128(_: u128, _: u128) -> u128 + fn __shr_u128(_: u128, _: u128) -> u128 + fn __bitand_u128(_: u128, _: u128) -> u128 + fn __bitor_u128(_: u128, _: u128) -> u128 + fn __bitxor_u128(_: u128, _: u128) -> u128 + + fn __eq_u128(_: u128, _: u128) -> bool + fn __ne_u128(_: u128, _: u128) -> bool + fn __lt_u128(_: u128, _: u128) -> bool + fn __le_u128(_: u128, _: u128) -> bool + fn __gt_u128(_: u128, _: u128) -> bool + fn __ge_u128(_: u128, _: u128) -> bool + + fn __bitnot_u128(_: u128) -> u128 +} + +// Extern intrinsics for usize +extern { + fn __add_usize(_: usize, _: usize) -> usize + fn __sub_usize(_: usize, _: usize) -> usize + fn __mul_usize(_: usize, _: usize) -> usize + fn __div_usize(_: usize, _: usize) -> usize + fn __rem_usize(_: usize, _: usize) -> usize + fn __pow_usize(_: usize, _: usize) -> usize + fn __shl_usize(_: usize, _: usize) -> usize + fn __shr_usize(_: usize, _: usize) -> usize + fn __bitand_usize(_: usize, _: usize) -> usize + fn __bitor_usize(_: usize, _: usize) -> usize + fn __bitxor_usize(_: usize, _: usize) -> usize + + fn __eq_usize(_: usize, _: usize) -> bool + fn __ne_usize(_: usize, _: usize) -> bool + fn __lt_usize(_: usize, _: usize) -> bool + fn __le_usize(_: usize, _: usize) -> bool + fn __gt_usize(_: usize, _: usize) -> bool + fn __ge_usize(_: usize, _: usize) -> bool + + fn __bitnot_usize(_: usize) -> usize +} + +// Extern intrinsics for i256 +extern { + fn __add_i256(_: i256, _: i256) -> i256 + fn __sub_i256(_: i256, _: i256) -> i256 + fn __mul_i256(_: i256, _: i256) -> i256 + fn __div_i256(_: i256, _: i256) -> i256 + fn __rem_i256(_: i256, _: i256) -> i256 + fn __pow_i256(_: i256, _: i256) -> i256 + fn __shl_i256(_: i256, _: i256) -> i256 + fn __shr_i256(_: i256, _: i256) -> i256 + fn __bitand_i256(_: i256, _: i256) -> i256 + fn __bitor_i256(_: i256, _: i256) -> i256 + fn __bitxor_i256(_: i256, _: i256) -> i256 + + fn __eq_i256(_: i256, _: i256) -> bool + fn __ne_i256(_: i256, _: i256) -> bool + fn __lt_i256(_: i256, _: i256) -> bool + fn __le_i256(_: i256, _: i256) -> bool + fn __gt_i256(_: i256, _: i256) -> bool + fn __ge_i256(_: i256, _: i256) -> bool + + fn __neg_i256(_: i256) -> i256 + fn __bitnot_i256(_: i256) -> i256 +} + +// Extern intrinsics for u256 +extern { + fn __add_u256(_: u256, _: u256) -> u256 + fn __sub_u256(_: u256, _: u256) -> u256 + fn __mul_u256(_: u256, _: u256) -> u256 + fn __div_u256(_: u256, _: u256) -> u256 + fn __rem_u256(_: u256, _: u256) -> u256 + fn __pow_u256(_: u256, _: u256) -> u256 + fn __shl_u256(_: u256, _: u256) -> u256 + fn __shr_u256(_: u256, _: u256) -> u256 + fn __bitand_u256(_: u256, _: u256) -> u256 + fn __bitor_u256(_: u256, _: u256) -> u256 + fn __bitxor_u256(_: u256, _: u256) -> u256 + + fn __eq_u256(_: u256, _: u256) -> bool + fn __ne_u256(_: u256, _: u256) -> bool + fn __lt_u256(_: u256, _: u256) -> bool + fn __le_u256(_: u256, _: u256) -> bool + fn __gt_u256(_: u256, _: u256) -> bool + fn __ge_u256(_: u256, _: u256) -> bool + + fn __bitnot_u256(_: u256) -> u256 +} + +// Extern intrinsics for isize +extern { + fn __add_isize(_: isize, _: isize) -> isize + fn __sub_isize(_: isize, _: isize) -> isize + fn __mul_isize(_: isize, _: isize) -> isize + fn __div_isize(_: isize, _: isize) -> isize + fn __rem_isize(_: isize, _: isize) -> isize + fn __pow_isize(_: isize, _: isize) -> isize + fn __shl_isize(_: isize, _: isize) -> isize + fn __shr_isize(_: isize, _: isize) -> isize + fn __bitand_isize(_: isize, _: isize) -> isize + fn __bitor_isize(_: isize, _: isize) -> isize + fn __bitxor_isize(_: isize, _: isize) -> isize + + fn __eq_isize(_: isize, _: isize) -> bool + fn __ne_isize(_: isize, _: isize) -> bool + fn __lt_isize(_: isize, _: isize) -> bool + fn __le_isize(_: isize, _: isize) -> bool + fn __gt_isize(_: isize, _: isize) -> bool + fn __ge_isize(_: isize, _: isize) -> bool + + fn __neg_isize(_: isize) -> isize + fn __bitnot_isize(_: isize) -> isize +} + +// Extern intrinsics for bool +extern { + fn __not_bool(_: bool) -> bool + fn __bitand_bool(_: bool, _: bool) -> bool + fn __bitor_bool(_: bool, _: bool) -> bool + fn __bitxor_bool(_: bool, _: bool) -> bool + fn __eq_bool(_: bool, _: bool) -> bool + fn __ne_bool(_: bool, _: bool) -> bool +} + +// u8 impls +impl BitNot for u8 { fn bit_not(self) -> u8 { __bitnot_u8(self) } } +impl Add for u8 { fn add(self, _ other: u8) -> u8 { __add_u8(self, other) } } +impl Sub for u8 { fn sub(self, _ other: u8) -> u8 { __sub_u8(self, other) } } +impl Mul for u8 { fn mul(self, _ other: u8) -> u8 { __mul_u8(self, other) } } +impl Div for u8 { fn div(self, _ other: u8) -> u8 { __div_u8(self, other) } } +impl Rem for u8 { fn rem(self, _ other: u8) -> u8 { __rem_u8(self, other) } } +impl Pow for u8 { fn pow(self, _ other: u8) -> u8 { __pow_u8(self, other) } } +impl Shl for u8 { fn shl(self, _ other: u8) -> u8 { __shl_u8(self, other) } } +impl Shr for u8 { fn shr(self, _ other: u8) -> u8 { __shr_u8(self, other) } } +impl BitAnd for u8 { fn bitand(self, _ other: u8) -> u8 { __bitand_u8(self, other) } } +impl BitOr for u8 { fn bitor(self, _ other: u8) -> u8 { __bitor_u8(self, other) } } +impl BitXor for u8 { fn bitxor(self, _ other: u8) -> u8 { __bitxor_u8(self, other) } } +impl Eq for u8 { + fn eq(self, _ other: u8) -> bool { __eq_u8(self, other) } + fn ne(self, _ other: u8) -> bool { __ne_u8(self, other) } +} +impl Ord for u8 { + fn lt(self, _ other: u8) -> bool { __lt_u8(self, other) } + fn le(self, _ other: u8) -> bool { __le_u8(self, other) } + fn gt(self, _ other: u8) -> bool { __gt_u8(self, other) } + fn ge(self, _ other: u8) -> bool { __ge_u8(self, other) } +} +impl AddAssign for u8 { fn add_assign(mut self, _ other: u8) { self = self + other } } +impl SubAssign for u8 { fn sub_assign(mut self, _ other: u8) { self = self - other } } +impl MulAssign for u8 { fn mul_assign(mut self, _ other: u8) { self = self * other } } +impl DivAssign for u8 { fn div_assign(mut self, _ other: u8) { self = self / other } } +impl RemAssign for u8 { fn rem_assign(mut self, _ other: u8) { self = self % other } } +impl PowAssign for u8 { fn pow_assign(mut self, _ other: u8) { self = self ** other } } +impl ShlAssign for u8 { fn shl_assign(mut self, _ other: u8) { self = self << other } } +impl ShrAssign for u8 { fn shr_assign(mut self, _ other: u8) { self = self >> other } } +impl BitAndAssign for u8 { fn bitand_assign(mut self, _ other: u8) { self = self & other } } +impl BitOrAssign for u8 { fn bitor_assign(mut self, _ other: u8) { self = self | other } } +impl BitXorAssign for u8 { fn bitxor_assign(mut self, _ other: u8) { self = self ^ other } } +impl Default for u8 { fn default() -> Self { 0 } } + +// i8 impls +impl Neg for i8 { fn neg(self) -> i8 { __neg_i8(self) } } +impl BitNot for i8 { fn bit_not(self) -> i8 { __bitnot_i8(self) } } +impl Add for i8 { fn add(self, _ other: i8) -> i8 { __add_i8(self, other) } } +impl Sub for i8 { fn sub(self, _ other: i8) -> i8 { __sub_i8(self, other) } } +impl Mul for i8 { fn mul(self, _ other: i8) -> i8 { __mul_i8(self, other) } } +impl Div for i8 { fn div(self, _ other: i8) -> i8 { __div_i8(self, other) } } +impl Rem for i8 { fn rem(self, _ other: i8) -> i8 { __rem_i8(self, other) } } +impl Pow for i8 { fn pow(self, _ other: i8) -> i8 { __pow_i8(self, other) } } +impl Shl for i8 { fn shl(self, _ other: i8) -> i8 { __shl_i8(self, other) } } +impl Shr for i8 { fn shr(self, _ other: i8) -> i8 { __shr_i8(self, other) } } +impl BitAnd for i8 { fn bitand(self, _ other: i8) -> i8 { __bitand_i8(self, other) } } +impl BitOr for i8 { fn bitor(self, _ other: i8) -> i8 { __bitor_i8(self, other) } } +impl BitXor for i8 { fn bitxor(self, _ other: i8) -> i8 { __bitxor_i8(self, other) } } +impl Eq for i8 { + fn eq(self, _ other: i8) -> bool { __eq_i8(self, other) } + fn ne(self, _ other: i8) -> bool { __ne_i8(self, other) } +} +impl Ord for i8 { + fn lt(self, _ other: i8) -> bool { __lt_i8(self, other) } + fn le(self, _ other: i8) -> bool { __le_i8(self, other) } + fn gt(self, _ other: i8) -> bool { __gt_i8(self, other) } + fn ge(self, _ other: i8) -> bool { __ge_i8(self, other) } +} +impl AddAssign for i8 { fn add_assign(mut self, _ other: i8) { self = self + other } } +impl SubAssign for i8 { fn sub_assign(mut self, _ other: i8) { self = self - other } } +impl MulAssign for i8 { fn mul_assign(mut self, _ other: i8) { self = self * other } } +impl DivAssign for i8 { fn div_assign(mut self, _ other: i8) { self = self / other } } +impl RemAssign for i8 { fn rem_assign(mut self, _ other: i8) { self = self % other } } +impl PowAssign for i8 { fn pow_assign(mut self, _ other: i8) { self = self ** other } } +impl ShlAssign for i8 { fn shl_assign(mut self, _ other: i8) { self = self << other } } +impl ShrAssign for i8 { fn shr_assign(mut self, _ other: i8) { self = self >> other } } +impl BitAndAssign for i8 { fn bitand_assign(mut self, _ other: i8) { self = self & other } } +impl BitOrAssign for i8 { fn bitor_assign(mut self, _ other: i8) { self = self | other } } +impl BitXorAssign for i8 { fn bitxor_assign(mut self, _ other: i8) { self = self ^ other } } +impl Default for i8 { fn default() -> Self { 0 } } + +// i16 impls +impl Neg for i16 { fn neg(self) -> i16 { __neg_i16(self) } } +impl BitNot for i16 { fn bit_not(self) -> i16 { __bitnot_i16(self) } } +impl Add for i16 { fn add(self, _ other: i16) -> i16 { __add_i16(self, other) } } +impl Sub for i16 { fn sub(self, _ other: i16) -> i16 { __sub_i16(self, other) } } +impl Mul for i16 { fn mul(self, _ other: i16) -> i16 { __mul_i16(self, other) } } +impl Div for i16 { fn div(self, _ other: i16) -> i16 { __div_i16(self, other) } } +impl Rem for i16 { fn rem(self, _ other: i16) -> i16 { __rem_i16(self, other) } } +impl Pow for i16 { fn pow(self, _ other: i16) -> i16 { __pow_i16(self, other) } } +impl Shl for i16 { fn shl(self, _ other: i16) -> i16 { __shl_i16(self, other) } } +impl Shr for i16 { fn shr(self, _ other: i16) -> i16 { __shr_i16(self, other) } } +impl BitAnd for i16 { fn bitand(self, _ other: i16) -> i16 { __bitand_i16(self, other) } } +impl BitOr for i16 { fn bitor(self, _ other: i16) -> i16 { __bitor_i16(self, other) } } +impl BitXor for i16 { fn bitxor(self, _ other: i16) -> i16 { __bitxor_i16(self, other) } } +impl Eq for i16 { + fn eq(self, _ other: i16) -> bool { __eq_i16(self, other) } + fn ne(self, _ other: i16) -> bool { __ne_i16(self, other) } +} +impl Ord for i16 { + fn lt(self, _ other: i16) -> bool { __lt_i16(self, other) } + fn le(self, _ other: i16) -> bool { __le_i16(self, other) } + fn gt(self, _ other: i16) -> bool { __gt_i16(self, other) } + fn ge(self, _ other: i16) -> bool { __ge_i16(self, other) } +} +impl AddAssign for i16 { fn add_assign(mut self, _ other: i16) { self = self + other } } +impl SubAssign for i16 { fn sub_assign(mut self, _ other: i16) { self = self - other } } +impl MulAssign for i16 { fn mul_assign(mut self, _ other: i16) { self = self * other } } +impl DivAssign for i16 { fn div_assign(mut self, _ other: i16) { self = self / other } } +impl RemAssign for i16 { fn rem_assign(mut self, _ other: i16) { self = self % other } } +impl PowAssign for i16 { fn pow_assign(mut self, _ other: i16) { self = self ** other } } +impl ShlAssign for i16 { fn shl_assign(mut self, _ other: i16) { self = self << other } } +impl ShrAssign for i16 { fn shr_assign(mut self, _ other: i16) { self = self >> other } } +impl BitAndAssign for i16 { fn bitand_assign(mut self, _ other: i16) { self = self & other } } +impl BitOrAssign for i16 { fn bitor_assign(mut self, _ other: i16) { self = self | other } } +impl BitXorAssign for i16 { fn bitxor_assign(mut self, _ other: i16) { self = self ^ other } } +impl Default for i16 { fn default() -> Self { 0 } } + +// u16 impls +impl BitNot for u16 { fn bit_not(self) -> u16 { __bitnot_u16(self) } } +impl Add for u16 { fn add(self, _ other: u16) -> u16 { __add_u16(self, other) } } +impl Sub for u16 { fn sub(self, _ other: u16) -> u16 { __sub_u16(self, other) } } +impl Mul for u16 { fn mul(self, _ other: u16) -> u16 { __mul_u16(self, other) } } +impl Div for u16 { fn div(self, _ other: u16) -> u16 { __div_u16(self, other) } } +impl Rem for u16 { fn rem(self, _ other: u16) -> u16 { __rem_u16(self, other) } } +impl Pow for u16 { fn pow(self, _ other: u16) -> u16 { __pow_u16(self, other) } } +impl Shl for u16 { fn shl(self, _ other: u16) -> u16 { __shl_u16(self, other) } } +impl Shr for u16 { fn shr(self, _ other: u16) -> u16 { __shr_u16(self, other) } } +impl BitAnd for u16 { fn bitand(self, _ other: u16) -> u16 { __bitand_u16(self, other) } } +impl BitOr for u16 { fn bitor(self, _ other: u16) -> u16 { __bitor_u16(self, other) } } +impl BitXor for u16 { fn bitxor(self, _ other: u16) -> u16 { __bitxor_u16(self, other) } } +impl Eq for u16 { + fn eq(self, _ other: u16) -> bool { __eq_u16(self, other) } + fn ne(self, _ other: u16) -> bool { __ne_u16(self, other) } +} +impl Ord for u16 { + fn lt(self, _ other: u16) -> bool { __lt_u16(self, other) } + fn le(self, _ other: u16) -> bool { __le_u16(self, other) } + fn gt(self, _ other: u16) -> bool { __gt_u16(self, other) } + fn ge(self, _ other: u16) -> bool { __ge_u16(self, other) } +} +impl AddAssign for u16 { fn add_assign(mut self, _ other: u16) { self = self + other } } +impl SubAssign for u16 { fn sub_assign(mut self, _ other: u16) { self = self - other } } +impl MulAssign for u16 { fn mul_assign(mut self, _ other: u16) { self = self * other } } +impl DivAssign for u16 { fn div_assign(mut self, _ other: u16) { self = self / other } } +impl RemAssign for u16 { fn rem_assign(mut self, _ other: u16) { self = self % other } } +impl PowAssign for u16 { fn pow_assign(mut self, _ other: u16) { self = self ** other } } +impl ShlAssign for u16 { fn shl_assign(mut self, _ other: u16) { self = self << other } } +impl ShrAssign for u16 { fn shr_assign(mut self, _ other: u16) { self = self >> other } } +impl BitAndAssign for u16 { fn bitand_assign(mut self, _ other: u16) { self = self & other } } +impl BitOrAssign for u16 { fn bitor_assign(mut self, _ other: u16) { self = self | other } } +impl BitXorAssign for u16 { fn bitxor_assign(mut self, _ other: u16) { self = self ^ other } } +impl Default for u16 { fn default() -> Self { 0 } } + + +// i32 impls +impl Neg for i32 { fn neg(self) -> i32 { __neg_i32(self) } } +impl BitNot for i32 { fn bit_not(self) -> i32 { __bitnot_i32(self) } } +impl Add for i32 { fn add(self, _ other: i32) -> i32 { __add_i32(self, other) } } +impl Sub for i32 { fn sub(self, _ other: i32) -> i32 { __sub_i32(self, other) } } +impl Mul for i32 { fn mul(self, _ other: i32) -> i32 { __mul_i32(self, other) } } +impl Div for i32 { fn div(self, _ other: i32) -> i32 { __div_i32(self, other) } } +impl Rem for i32 { fn rem(self, _ other: i32) -> i32 { __rem_i32(self, other) } } +impl Pow for i32 { fn pow(self, _ other: i32) -> i32 { __pow_i32(self, other) } } +impl Shl for i32 { fn shl(self, _ other: i32) -> i32 { __shl_i32(self, other) } } +impl Shr for i32 { fn shr(self, _ other: i32) -> i32 { __shr_i32(self, other) } } +impl BitAnd for i32 { fn bitand(self, _ other: i32) -> i32 { __bitand_i32(self, other) } } +impl BitOr for i32 { fn bitor(self, _ other: i32) -> i32 { __bitor_i32(self, other) } } +impl BitXor for i32 { fn bitxor(self, _ other: i32) -> i32 { __bitxor_i32(self, other) } } +impl Eq for i32 { + fn eq(self, _ other: i32) -> bool { __eq_i32(self, other) } + fn ne(self, _ other: i32) -> bool { __ne_i32(self, other) } +} +impl Ord for i32 { + fn lt(self, _ other: i32) -> bool { __lt_i32(self, other) } + fn le(self, _ other: i32) -> bool { __le_i32(self, other) } + fn gt(self, _ other: i32) -> bool { __gt_i32(self, other) } + fn ge(self, _ other: i32) -> bool { __ge_i32(self, other) } +} +impl AddAssign for i32 { fn add_assign(mut self, _ other: i32) { self = self + other } } +impl SubAssign for i32 { fn sub_assign(mut self, _ other: i32) { self = self - other } } +impl MulAssign for i32 { fn mul_assign(mut self, _ other: i32) { self = self * other } } +impl DivAssign for i32 { fn div_assign(mut self, _ other: i32) { self = self / other } } +impl RemAssign for i32 { fn rem_assign(mut self, _ other: i32) { self = self % other } } +impl PowAssign for i32 { fn pow_assign(mut self, _ other: i32) { self = self ** other } } +impl ShlAssign for i32 { fn shl_assign(mut self, _ other: i32) { self = self << other } } +impl ShrAssign for i32 { fn shr_assign(mut self, _ other: i32) { self = self >> other } } +impl BitAndAssign for i32 { fn bitand_assign(mut self, _ other: i32) { self = self & other } } +impl BitOrAssign for i32 { fn bitor_assign(mut self, _ other: i32) { self = self | other } } +impl BitXorAssign for i32 { fn bitxor_assign(mut self, _ other: i32) { self = self ^ other } } +impl Default for i32 { fn default() -> Self { 0 } } + +// u32 impls +impl BitNot for u32 { fn bit_not(self) -> u32 { __bitnot_u32(self) } } +impl Add for u32 { fn add(self, _ other: u32) -> u32 { __add_u32(self, other) } } +impl Sub for u32 { fn sub(self, _ other: u32) -> u32 { __sub_u32(self, other) } } +impl Mul for u32 { fn mul(self, _ other: u32) -> u32 { __mul_u32(self, other) } } +impl Div for u32 { fn div(self, _ other: u32) -> u32 { __div_u32(self, other) } } +impl Rem for u32 { fn rem(self, _ other: u32) -> u32 { __rem_u32(self, other) } } +impl Pow for u32 { fn pow(self, _ other: u32) -> u32 { __pow_u32(self, other) } } +impl Shl for u32 { fn shl(self, _ other: u32) -> u32 { __shl_u32(self, other) } } +impl Shr for u32 { fn shr(self, _ other: u32) -> u32 { __shr_u32(self, other) } } +impl BitAnd for u32 { fn bitand(self, _ other: u32) -> u32 { __bitand_u32(self, other) } } +impl BitOr for u32 { fn bitor(self, _ other: u32) -> u32 { __bitor_u32(self, other) } } +impl BitXor for u32 { fn bitxor(self, _ other: u32) -> u32 { __bitxor_u32(self, other) } } +impl Eq for u32 { + fn eq(self, _ other: u32) -> bool { __eq_u32(self, other) } + fn ne(self, _ other: u32) -> bool { __ne_u32(self, other) } +} +impl Ord for u32 { + fn lt(self, _ other: u32) -> bool { __lt_u32(self, other) } + fn le(self, _ other: u32) -> bool { __le_u32(self, other) } + fn gt(self, _ other: u32) -> bool { __gt_u32(self, other) } + fn ge(self, _ other: u32) -> bool { __ge_u32(self, other) } +} +impl AddAssign for u32 { fn add_assign(mut self, _ other: u32) { self = self + other } } +impl SubAssign for u32 { fn sub_assign(mut self, _ other: u32) { self = self - other } } +impl MulAssign for u32 { fn mul_assign(mut self, _ other: u32) { self = self * other } } +impl DivAssign for u32 { fn div_assign(mut self, _ other: u32) { self = self / other } } +impl RemAssign for u32 { fn rem_assign(mut self, _ other: u32) { self = self % other } } +impl PowAssign for u32 { fn pow_assign(mut self, _ other: u32) { self = self ** other } } +impl ShlAssign for u32 { fn shl_assign(mut self, _ other: u32) { self = self << other } } +impl ShrAssign for u32 { fn shr_assign(mut self, _ other: u32) { self = self >> other } } +impl BitAndAssign for u32 { fn bitand_assign(mut self, _ other: u32) { self = self & other } } +impl BitOrAssign for u32 { fn bitor_assign(mut self, _ other: u32) { self = self | other } } +impl BitXorAssign for u32 { fn bitxor_assign(mut self, _ other: u32) { self = self ^ other } } +impl Default for u32 { fn default() -> Self { 0 } } + +// i64 impls +impl Neg for i64 { fn neg(self) -> i64 { __neg_i64(self) } } +impl BitNot for i64 { fn bit_not(self) -> i64 { __bitnot_i64(self) } } +impl Add for i64 { fn add(self, _ other: i64) -> i64 { __add_i64(self, other) } } +impl Sub for i64 { fn sub(self, _ other: i64) -> i64 { __sub_i64(self, other) } } +impl Mul for i64 { fn mul(self, _ other: i64) -> i64 { __mul_i64(self, other) } } +impl Div for i64 { fn div(self, _ other: i64) -> i64 { __div_i64(self, other) } } +impl Rem for i64 { fn rem(self, _ other: i64) -> i64 { __rem_i64(self, other) } } +impl Pow for i64 { fn pow(self, _ other: i64) -> i64 { __pow_i64(self, other) } } +impl Shl for i64 { fn shl(self, _ other: i64) -> i64 { __shl_i64(self, other) } } +impl Shr for i64 { fn shr(self, _ other: i64) -> i64 { __shr_i64(self, other) } } +impl BitAnd for i64 { fn bitand(self, _ other: i64) -> i64 { __bitand_i64(self, other) } } +impl BitOr for i64 { fn bitor(self, _ other: i64) -> i64 { __bitor_i64(self, other) } } +impl BitXor for i64 { fn bitxor(self, _ other: i64) -> i64 { __bitxor_i64(self, other) } } +impl Eq for i64 { + fn eq(self, _ other: i64) -> bool { __eq_i64(self, other) } + fn ne(self, _ other: i64) -> bool { __ne_i64(self, other) } +} +impl Ord for i64 { + fn lt(self, _ other: i64) -> bool { __lt_i64(self, other) } + fn le(self, _ other: i64) -> bool { __le_i64(self, other) } + fn gt(self, _ other: i64) -> bool { __gt_i64(self, other) } + fn ge(self, _ other: i64) -> bool { __ge_i64(self, other) } +} +impl AddAssign for i64 { fn add_assign(mut self, _ other: i64) { self = self + other } } +impl SubAssign for i64 { fn sub_assign(mut self, _ other: i64) { self = self - other } } +impl MulAssign for i64 { fn mul_assign(mut self, _ other: i64) { self = self * other } } +impl DivAssign for i64 { fn div_assign(mut self, _ other: i64) { self = self / other } } +impl RemAssign for i64 { fn rem_assign(mut self, _ other: i64) { self = self % other } } +impl PowAssign for i64 { fn pow_assign(mut self, _ other: i64) { self = self ** other } } +impl ShlAssign for i64 { fn shl_assign(mut self, _ other: i64) { self = self << other } } +impl ShrAssign for i64 { fn shr_assign(mut self, _ other: i64) { self = self >> other } } +impl BitAndAssign for i64 { fn bitand_assign(mut self, _ other: i64) { self = self & other } } +impl BitOrAssign for i64 { fn bitor_assign(mut self, _ other: i64) { self = self | other } } +impl BitXorAssign for i64 { fn bitxor_assign(mut self, _ other: i64) { self = self ^ other } } +impl Default for i64 { fn default() -> Self { 0 } } + +// i128 impls +impl Neg for i128 { fn neg(self) -> i128 { __neg_i128(self) } } +impl BitNot for i128 { fn bit_not(self) -> i128 { __bitnot_i128(self) } } +impl Add for i128 { fn add(self, _ other: i128) -> i128 { __add_i128(self, other) } } +impl Sub for i128 { fn sub(self, _ other: i128) -> i128 { __sub_i128(self, other) } } +impl Mul for i128 { fn mul(self, _ other: i128) -> i128 { __mul_i128(self, other) } } +impl Div for i128 { fn div(self, _ other: i128) -> i128 { __div_i128(self, other) } } +impl Rem for i128 { fn rem(self, _ other: i128) -> i128 { __rem_i128(self, other) } } +impl Pow for i128 { fn pow(self, _ other: i128) -> i128 { __pow_i128(self, other) } } +impl Shl for i128 { fn shl(self, _ other: i128) -> i128 { __shl_i128(self, other) } } +impl Shr for i128 { fn shr(self, _ other: i128) -> i128 { __shr_i128(self, other) } } +impl BitAnd for i128 { fn bitand(self, _ other: i128) -> i128 { __bitand_i128(self, other) } } +impl BitOr for i128 { fn bitor(self, _ other: i128) -> i128 { __bitor_i128(self, other) } } +impl BitXor for i128 { fn bitxor(self, _ other: i128) -> i128 { __bitxor_i128(self, other) } } +impl Eq for i128 { + fn eq(self, _ other: i128) -> bool { __eq_i128(self, other) } + fn ne(self, _ other: i128) -> bool { __ne_i128(self, other) } +} +impl Ord for i128 { + fn lt(self, _ other: i128) -> bool { __lt_i128(self, other) } + fn le(self, _ other: i128) -> bool { __le_i128(self, other) } + fn gt(self, _ other: i128) -> bool { __gt_i128(self, other) } + fn ge(self, _ other: i128) -> bool { __ge_i128(self, other) } +} +impl AddAssign for i128 { fn add_assign(mut self, _ other: i128) { self = self + other } } +impl SubAssign for i128 { fn sub_assign(mut self, _ other: i128) { self = self - other } } +impl MulAssign for i128 { fn mul_assign(mut self, _ other: i128) { self = self * other } } +impl DivAssign for i128 { fn div_assign(mut self, _ other: i128) { self = self / other } } +impl RemAssign for i128 { fn rem_assign(mut self, _ other: i128) { self = self % other } } +impl PowAssign for i128 { fn pow_assign(mut self, _ other: i128) { self = self ** other } } +impl ShlAssign for i128 { fn shl_assign(mut self, _ other: i128) { self = self << other } } +impl ShrAssign for i128 { fn shr_assign(mut self, _ other: i128) { self = self >> other } } +impl BitAndAssign for i128 { fn bitand_assign(mut self, _ other: i128) { self = self & other } } +impl BitOrAssign for i128 { fn bitor_assign(mut self, _ other: i128) { self = self | other } } +impl BitXorAssign for i128 { fn bitxor_assign(mut self, _ other: i128) { self = self ^ other } } +impl Default for i128 { fn default() -> Self { 0 } } + +// u64 impls +impl BitNot for u64 { fn bit_not(self) -> u64 { __bitnot_u64(self) } } +impl Add for u64 { fn add(self, _ other: u64) -> u64 { __add_u64(self, other) } } +impl Sub for u64 { fn sub(self, _ other: u64) -> u64 { __sub_u64(self, other) } } +impl Mul for u64 { fn mul(self, _ other: u64) -> u64 { __mul_u64(self, other) } } +impl Div for u64 { fn div(self, _ other: u64) -> u64 { __div_u64(self, other) } } +impl Rem for u64 { fn rem(self, _ other: u64) -> u64 { __rem_u64(self, other) } } +impl Pow for u64 { fn pow(self, _ other: u64) -> u64 { __pow_u64(self, other) } } +impl Shl for u64 { fn shl(self, _ other: u64) -> u64 { __shl_u64(self, other) } } +impl Shr for u64 { fn shr(self, _ other: u64) -> u64 { __shr_u64(self, other) } } +impl BitAnd for u64 { fn bitand(self, _ other: u64) -> u64 { __bitand_u64(self, other) } } +impl BitOr for u64 { fn bitor(self, _ other: u64) -> u64 { __bitor_u64(self, other) } } +impl BitXor for u64 { fn bitxor(self, _ other: u64) -> u64 { __bitxor_u64(self, other) } } +impl Eq for u64 { + fn eq(self, _ other: u64) -> bool { __eq_u64(self, other) } + fn ne(self, _ other: u64) -> bool { __ne_u64(self, other) } +} +impl Ord for u64 { + fn lt(self, _ other: u64) -> bool { __lt_u64(self, other) } + fn le(self, _ other: u64) -> bool { __le_u64(self, other) } + fn gt(self, _ other: u64) -> bool { __gt_u64(self, other) } + fn ge(self, _ other: u64) -> bool { __ge_u64(self, other) } +} +impl AddAssign for u64 { fn add_assign(mut self, _ other: u64) { self = self + other } } +impl SubAssign for u64 { fn sub_assign(mut self, _ other: u64) { self = self - other } } +impl MulAssign for u64 { fn mul_assign(mut self, _ other: u64) { self = self * other } } +impl DivAssign for u64 { fn div_assign(mut self, _ other: u64) { self = self / other } } +impl RemAssign for u64 { fn rem_assign(mut self, _ other: u64) { self = self % other } } +impl PowAssign for u64 { fn pow_assign(mut self, _ other: u64) { self = self ** other } } +impl ShlAssign for u64 { fn shl_assign(mut self, _ other: u64) { self = self << other } } +impl ShrAssign for u64 { fn shr_assign(mut self, _ other: u64) { self = self >> other } } +impl BitAndAssign for u64 { fn bitand_assign(mut self, _ other: u64) { self = self & other } } +impl BitOrAssign for u64 { fn bitor_assign(mut self, _ other: u64) { self = self | other } } +impl BitXorAssign for u64 { fn bitxor_assign(mut self, _ other: u64) { self = self ^ other } } +impl Default for u64 { fn default() -> Self { 0 } } + +// u128 impls +impl BitNot for u128 { fn bit_not(self) -> u128 { __bitnot_u128(self) } } +impl Add for u128 { fn add(self, _ other: u128) -> u128 { __add_u128(self, other) } } +impl Sub for u128 { fn sub(self, _ other: u128) -> u128 { __sub_u128(self, other) } } +impl Mul for u128 { fn mul(self, _ other: u128) -> u128 { __mul_u128(self, other) } } +impl Div for u128 { fn div(self, _ other: u128) -> u128 { __div_u128(self, other) } } +impl Rem for u128 { fn rem(self, _ other: u128) -> u128 { __rem_u128(self, other) } } +impl Pow for u128 { fn pow(self, _ other: u128) -> u128 { __pow_u128(self, other) } } +impl Shl for u128 { fn shl(self, _ other: u128) -> u128 { __shl_u128(self, other) } } +impl Shr for u128 { fn shr(self, _ other: u128) -> u128 { __shr_u128(self, other) } } +impl BitAnd for u128 { fn bitand(self, _ other: u128) -> u128 { __bitand_u128(self, other) } } +impl BitOr for u128 { fn bitor(self, _ other: u128) -> u128 { __bitor_u128(self, other) } } +impl BitXor for u128 { fn bitxor(self, _ other: u128) -> u128 { __bitxor_u128(self, other) } } +impl Eq for u128 { + fn eq(self, _ other: u128) -> bool { __eq_u128(self, other) } + fn ne(self, _ other: u128) -> bool { __ne_u128(self, other) } +} +impl Ord for u128 { + fn lt(self, _ other: u128) -> bool { __lt_u128(self, other) } + fn le(self, _ other: u128) -> bool { __le_u128(self, other) } + fn gt(self, _ other: u128) -> bool { __gt_u128(self, other) } + fn ge(self, _ other: u128) -> bool { __ge_u128(self, other) } +} +impl AddAssign for u128 { fn add_assign(mut self, _ other: u128) { self = self + other } } +impl SubAssign for u128 { fn sub_assign(mut self, _ other: u128) { self = self - other } } +impl MulAssign for u128 { fn mul_assign(mut self, _ other: u128) { self = self * other } } +impl DivAssign for u128 { fn div_assign(mut self, _ other: u128) { self = self / other } } +impl RemAssign for u128 { fn rem_assign(mut self, _ other: u128) { self = self % other } } +impl PowAssign for u128 { fn pow_assign(mut self, _ other: u128) { self = self ** other } } +impl ShlAssign for u128 { fn shl_assign(mut self, _ other: u128) { self = self << other } } +impl ShrAssign for u128 { fn shr_assign(mut self, _ other: u128) { self = self >> other } } +impl BitAndAssign for u128 { fn bitand_assign(mut self, _ other: u128) { self = self & other } } +impl BitOrAssign for u128 { fn bitor_assign(mut self, _ other: u128) { self = self | other } } +impl BitXorAssign for u128 { fn bitxor_assign(mut self, _ other: u128) { self = self ^ other } } +impl Default for u128 { fn default() -> Self { 0 } } + +// usize impls +impl BitNot for usize { fn bit_not(self) -> usize { __bitnot_usize(self) } } +impl Add for usize { fn add(self, _ other: usize) -> usize { __add_usize(self, other) } } +impl Sub for usize { fn sub(self, _ other: usize) -> usize { __sub_usize(self, other) } } +impl Mul for usize { fn mul(self, _ other: usize) -> usize { __mul_usize(self, other) } } +impl Div for usize { fn div(self, _ other: usize) -> usize { __div_usize(self, other) } } +impl Rem for usize { fn rem(self, _ other: usize) -> usize { __rem_usize(self, other) } } +impl Pow for usize { fn pow(self, _ other: usize) -> usize { __pow_usize(self, other) } } +impl Shl for usize { fn shl(self, _ other: usize) -> usize { __shl_usize(self, other) } } +impl Shr for usize { fn shr(self, _ other: usize) -> usize { __shr_usize(self, other) } } +impl BitAnd for usize { fn bitand(self, _ other: usize) -> usize { __bitand_usize(self, other) } } +impl BitOr for usize { fn bitor(self, _ other: usize) -> usize { __bitor_usize(self, other) } } +impl BitXor for usize { fn bitxor(self, _ other: usize) -> usize { __bitxor_usize(self, other) } } +impl Eq for usize { + fn eq(self, _ other: usize) -> bool { __eq_usize(self, other) } + fn ne(self, _ other: usize) -> bool { __ne_usize(self, other) } +} +impl Ord for usize { + fn lt(self, _ other: usize) -> bool { __lt_usize(self, other) } + fn le(self, _ other: usize) -> bool { __le_usize(self, other) } + fn gt(self, _ other: usize) -> bool { __gt_usize(self, other) } + fn ge(self, _ other: usize) -> bool { __ge_usize(self, other) } +} +impl Default for usize { fn default() -> Self { 0 } } + +// i256 impls +impl Neg for i256 { fn neg(self) -> i256 { __neg_i256(self) } } +impl BitNot for i256 { fn bit_not(self) -> i256 { __bitnot_i256(self) } } +impl Add for i256 { fn add(self, _ other: i256) -> i256 { __add_i256(self, other) } } +impl Sub for i256 { fn sub(self, _ other: i256) -> i256 { __sub_i256(self, other) } } +impl Mul for i256 { fn mul(self, _ other: i256) -> i256 { __mul_i256(self, other) } } +impl Div for i256 { fn div(self, _ other: i256) -> i256 { __div_i256(self, other) } } +impl Rem for i256 { fn rem(self, _ other: i256) -> i256 { __rem_i256(self, other) } } +impl Pow for i256 { fn pow(self, _ other: i256) -> i256 { __pow_i256(self, other) } } +impl Shl for i256 { fn shl(self, _ other: i256) -> i256 { __shl_i256(self, other) } } +impl Shr for i256 { fn shr(self, _ other: i256) -> i256 { __shr_i256(self, other) } } +impl BitAnd for i256 { fn bitand(self, _ other: i256) -> i256 { __bitand_i256(self, other) } } +impl BitOr for i256 { fn bitor(self, _ other: i256) -> i256 { __bitor_i256(self, other) } } +impl BitXor for i256 { fn bitxor(self, _ other: i256) -> i256 { __bitxor_i256(self, other) } } +impl Eq for i256 { + fn eq(self, _ other: i256) -> bool { __eq_i256(self, other) } + fn ne(self, _ other: i256) -> bool { __ne_i256(self, other) } +} +impl Ord for i256 { + fn lt(self, _ other: i256) -> bool { __lt_i256(self, other) } + fn le(self, _ other: i256) -> bool { __le_i256(self, other) } + fn gt(self, _ other: i256) -> bool { __gt_i256(self, other) } + fn ge(self, _ other: i256) -> bool { __ge_i256(self, other) } +} +impl AddAssign for i256 { fn add_assign(mut self, _ other: i256) { self = self + other } } +impl SubAssign for i256 { fn sub_assign(mut self, _ other: i256) { self = self - other } } +impl MulAssign for i256 { fn mul_assign(mut self, _ other: i256) { self = self * other } } +impl DivAssign for i256 { fn div_assign(mut self, _ other: i256) { self = self / other } } +impl RemAssign for i256 { fn rem_assign(mut self, _ other: i256) { self = self % other } } +impl PowAssign for i256 { fn pow_assign(mut self, _ other: i256) { self = self ** other } } +impl ShlAssign for i256 { fn shl_assign(mut self, _ other: i256) { self = self << other } } +impl ShrAssign for i256 { fn shr_assign(mut self, _ other: i256) { self = self >> other } } +impl BitAndAssign for i256 { fn bitand_assign(mut self, _ other: i256) { self = self & other } } +impl BitOrAssign for i256 { fn bitor_assign(mut self, _ other: i256) { self = self | other } } +impl BitXorAssign for i256 { fn bitxor_assign(mut self, _ other: i256) { self = self ^ other } } +impl Default for i256 { fn default() -> Self { 0 } } + +// u256 impls +impl BitNot for u256 { fn bit_not(self) -> u256 { __bitnot_u256(self) } } +impl Add for u256 { fn add(self, _ other: u256) -> u256 { __add_u256(self, other) } } +impl Sub for u256 { fn sub(self, _ other: u256) -> u256 { __sub_u256(self, other) } } +impl Mul for u256 { fn mul(self, _ other: u256) -> u256 { __mul_u256(self, other) } } +impl Div for u256 { fn div(self, _ other: u256) -> u256 { __div_u256(self, other) } } +impl Rem for u256 { fn rem(self, _ other: u256) -> u256 { __rem_u256(self, other) } } +impl Pow for u256 { fn pow(self, _ other: u256) -> u256 { __pow_u256(self, other) } } +impl Shl for u256 { fn shl(self, _ other: u256) -> u256 { __shl_u256(self, other) } } +impl Shr for u256 { fn shr(self, _ other: u256) -> u256 { __shr_u256(self, other) } } +impl BitAnd for u256 { fn bitand(self, _ other: u256) -> u256 { __bitand_u256(self, other) } } +impl BitOr for u256 { fn bitor(self, _ other: u256) -> u256 { __bitor_u256(self, other) } } +impl BitXor for u256 { fn bitxor(self, _ other: u256) -> u256 { __bitxor_u256(self, other) } } +impl Eq for u256 { + fn eq(self, _ other: u256) -> bool { __eq_u256(self, other) } + fn ne(self, _ other: u256) -> bool { __ne_u256(self, other) } +} +impl Ord for u256 { + fn lt(self, _ other: u256) -> bool { __lt_u256(self, other) } + fn le(self, _ other: u256) -> bool { __le_u256(self, other) } + fn gt(self, _ other: u256) -> bool { __gt_u256(self, other) } + fn ge(self, _ other: u256) -> bool { __ge_u256(self, other) } +} +impl AddAssign for u256 { fn add_assign(mut self, _ other: u256) { self = self + other } } +impl SubAssign for u256 { fn sub_assign(mut self, _ other: u256) { self = self - other } } +impl MulAssign for u256 { fn mul_assign(mut self, _ other: u256) { self = self * other } } +impl DivAssign for u256 { fn div_assign(mut self, _ other: u256) { self = self / other } } +impl RemAssign for u256 { fn rem_assign(mut self, _ other: u256) { self = self % other } } +impl PowAssign for u256 { fn pow_assign(mut self, _ other: u256) { self = self ** other } } +impl ShlAssign for u256 { fn shl_assign(mut self, _ other: u256) { self = self << other } } +impl ShrAssign for u256 { fn shr_assign(mut self, _ other: u256) { self = self >> other } } +impl BitAndAssign for u256 { fn bitand_assign(mut self, _ other: u256) { self = self & other } } +impl BitOrAssign for u256 { fn bitor_assign(mut self, _ other: u256) { self = self | other } } +impl BitXorAssign for u256 { fn bitxor_assign(mut self, _ other: u256) { self = self ^ other } } +impl Default for u256 { fn default() -> Self { 0 } } + +// isize impls +impl Neg for isize { fn neg(self) -> isize { __neg_isize(self) } } +impl BitNot for isize { fn bit_not(self) -> isize { __bitnot_isize(self) } } +impl Add for isize { fn add(self, _ other: isize) -> isize { __add_isize(self, other) } } +impl Sub for isize { fn sub(self, _ other: isize) -> isize { __sub_isize(self, other) } } +impl Mul for isize { fn mul(self, _ other: isize) -> isize { __mul_isize(self, other) } } +impl Div for isize { fn div(self, _ other: isize) -> isize { __div_isize(self, other) } } +impl Rem for isize { fn rem(self, _ other: isize) -> isize { __rem_isize(self, other) } } +impl Pow for isize { fn pow(self, _ other: isize) -> isize { __pow_isize(self, other) } } +impl Shl for isize { fn shl(self, _ other: isize) -> isize { __shl_isize(self, other) } } +impl Shr for isize { fn shr(self, _ other: isize) -> isize { __shr_isize(self, other) } } +impl BitAnd for isize { fn bitand(self, _ other: isize) -> isize { __bitand_isize(self, other) } } +impl BitOr for isize { fn bitor(self, _ other: isize) -> isize { __bitor_isize(self, other) } } +impl BitXor for isize { fn bitxor(self, _ other: isize) -> isize { __bitxor_isize(self, other) } } +impl Eq for isize { + fn eq(self, _ other: isize) -> bool { __eq_isize(self, other) } + fn ne(self, _ other: isize) -> bool { __ne_isize(self, other) } +} +impl Ord for isize { + fn lt(self, _ other: isize) -> bool { __lt_isize(self, other) } + fn le(self, _ other: isize) -> bool { __le_isize(self, other) } + fn gt(self, _ other: isize) -> bool { __gt_isize(self, other) } + fn ge(self, _ other: isize) -> bool { __ge_isize(self, other) } +} +impl AddAssign for isize { fn add_assign(mut self, _ other: isize) { self = self + other } } +impl SubAssign for isize { fn sub_assign(mut self, _ other: isize) { self = self - other } } +impl MulAssign for isize { fn mul_assign(mut self, _ other: isize) { self = self * other } } +impl DivAssign for isize { fn div_assign(mut self, _ other: isize) { self = self / other } } +impl RemAssign for isize { fn rem_assign(mut self, _ other: isize) { self = self % other } } +impl PowAssign for isize { fn pow_assign(mut self, _ other: isize) { self = self ** other } } +impl ShlAssign for isize { fn shl_assign(mut self, _ other: isize) { self = self << other } } +impl ShrAssign for isize { fn shr_assign(mut self, _ other: isize) { self = self >> other } } +impl BitAndAssign for isize { fn bitand_assign(mut self, _ other: isize) { self = self & other } } +impl BitOrAssign for isize { fn bitor_assign(mut self, _ other: isize) { self = self | other } } +impl BitXorAssign for isize { fn bitxor_assign(mut self, _ other: isize) { self = self ^ other } } +impl Default for isize { fn default() -> Self { 0 } } + +// bool impls +impl Not for bool { fn not(self) -> bool { __not_bool(self) } } +impl BitAnd for bool { fn bitand(self, _ other: bool) -> bool { __bitand_bool(self, other) } } +impl BitOr for bool { fn bitor(self, _ other: bool) -> bool { __bitor_bool(self, other) } } +impl BitXor for bool { fn bitxor(self, _ other: bool) -> bool { __bitxor_bool(self, other) } } +impl BitOrAssign for bool { fn bitor_assign(mut self, _ other: bool) { self = self | other } } +impl Eq for bool { + fn eq(self, _ other: bool) -> bool { __eq_bool(self, other) } + fn ne(self, _ other: bool) -> bool { __ne_bool(self, other) } +} +impl Default for bool { fn default() -> Self { false } } diff --git a/library/core/src/ops.fe b/library/core/src/ops.fe new file mode 100644 index 0000000000..4936ab103f --- /dev/null +++ b/library/core/src/ops.fe @@ -0,0 +1,150 @@ +pub trait Add { + type Output = Self + + fn add(self, _ other: T) -> Self::Output +} + +// Arithmetic binary operators +pub trait Sub { + type Output = Self + + fn sub(self, _ other: T) -> Self::Output +} + +pub trait Mul { + type Output = Self + fn mul(self, _ other: T) -> Self::Output +} + +pub trait Div { + type Output = Self + + fn div(self, _ other: T) -> Self::Output +} + +pub trait Rem { + type Output = Self + + fn rem(self, _ other: T) -> Self::Output +} + +pub trait Pow { + type Output = Self + + fn pow(self, _ other: T) -> Self::Output +} + +// Bitwise binary operators +pub trait BitAnd { + type Output = Self + + fn bitand(self, _ other: T) -> Self::Output +} + +pub trait BitOr { + type Output = Self + + fn bitor(self, _ other: T) -> Self::Output +} + +pub trait BitXor { + type Output = Self + + fn bitxor(self, _ other: T) -> Self::Output +} + +// Shift operators +pub trait Shl { + type Output = Self + + fn shl(self, _ other: T) -> Self::Output +} + +pub trait Shr { + type Output = Self + + fn shr(self, _ other: T) -> Self::Output +} + +pub trait Neg { + type Output = Self + + fn neg(self) -> Self::Output +} + +pub trait Not { + type Output = Self + + fn not(self) -> Self::Output +} + +pub trait BitNot { + type Output = Self + + fn bit_not(self) -> Self::Output +} + +// Comparison operators +pub trait Eq { + fn eq(self, _ other: T) -> bool + fn ne(self, _ other: T) -> bool +} + +pub trait Ord { + fn lt(self, _ other: T) -> bool + fn le(self, _ other: T) -> bool + fn gt(self, _ other: T) -> bool + fn ge(self, _ other: T) -> bool +} + +// Indexing operator +pub trait Index { + type Output + + fn index(self, _ index: I) -> Self::Output +} + +// Augmented assignment operators (return unit) +pub trait AddAssign { + fn add_assign(mut self, _ other: T) +} + +pub trait SubAssign { + fn sub_assign(mut self, _ other: T) +} + +pub trait MulAssign { + fn mul_assign(mut self, _ other: T) +} + +pub trait DivAssign { + fn div_assign(mut self, _ other: T) +} + +pub trait RemAssign { + fn rem_assign(mut self, _ other: T) +} + +pub trait PowAssign { + fn pow_assign(mut self, _ other: T) +} + +pub trait ShlAssign { + fn shl_assign(mut self, _ other: T) +} + +pub trait ShrAssign { + fn shr_assign(mut self, _ other: T) +} + +pub trait BitAndAssign { + fn bitand_assign(mut self, _ other: T) +} + +pub trait BitOrAssign { + fn bitor_assign(mut self, _ other: T) +} + +pub trait BitXorAssign { + fn bitxor_assign(mut self, _ other: T) +}