// Copyright (C) 2020-2023 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "optional.h" #include "rust-ast-full.h" #include "rust-late-name-resolver-2.0.h" #include "rust-default-resolver.h" #include "rust-path.h" #include "rust-tyty.h" #include "rust-hir-type-check.h" namespace Rust { namespace Resolver2_0 { Late::Late (NameResolutionContext &ctx) : DefaultResolver (ctx) {} void Late::setup_builtin_types () { auto next_id = [this] () { return ctx.mappings.get_next_hir_id (); }; static const std::pair builtins[] = { {"u8", new TyTy::UintType (next_id (), TyTy::UintType::U8)}, {"u16", new TyTy::UintType (next_id (), TyTy::UintType::U16)}, {"u32", new TyTy::UintType (next_id (), TyTy::UintType::U32)}, {"u64", new TyTy::UintType (next_id (), TyTy::UintType::U64)}, {"u128", new TyTy::UintType (next_id (), TyTy::UintType::U128)}, {"i8", new TyTy::IntType (next_id (), TyTy::IntType::I8)}, {"i16", new TyTy::IntType (next_id (), TyTy::IntType::I16)}, {"i32", new TyTy::IntType (next_id (), TyTy::IntType::I32)}, {"i64", new TyTy::IntType (next_id (), TyTy::IntType::I64)}, {"i128", new TyTy::IntType (next_id (), TyTy::IntType::I128)}, {"f32", new TyTy::FloatType (next_id (), TyTy::FloatType::F32)}, {"f64", new TyTy::FloatType (next_id (), TyTy::FloatType::F64)}, {"usize", new TyTy::USizeType (next_id ())}, {"isize", new TyTy::ISizeType (next_id ())}, // missing char, str, never, () // does name resolution play a part for this? or is it all at typechecking? // yeah it seems to be name resolution as well, which makes sense }; for (const auto &builtin : builtins) { // we should be able to use `insert_at_root` or `insert` here, since we're // at the root :) hopefully! auto ok = ctx.types.insert (builtin.first, builtin.second->get_ref () /* FIXME: Invalid! This returns an *HirId* */); rust_assert (ok); } } void Late::go (AST::Crate &crate) { setup_builtin_types (); for (auto &item : crate.items) item->accept_vis (*this); } void Late::new_label (Identifier name, NodeId id) { // labels can always shadow, so `insert` should never fail. if it does, we're // in big trouble! auto ok = ctx.labels.insert (name, id); rust_assert (ok); } void Late::visit (AST::LetStmt &let) { // so we don't need that method DefaultResolver::visit (let); // how do we deal with the fact that `let a = blipbloup` should look for a // label and cannot go through function ribs, but `let a = blipbloup()` can? // how do we insert ribs here, and only pop them when we exit the current // function? // keep a list of ribs to pop when a scope exits? so only for blocks? // how do we pop ribs that need to be popped not in order? // I think it's not important if we have shadowing, correct? // if we have shadowing, it should work! we'll see // ctx.insert(Identifier name, NodeId id, Namespace ns) // ctx.scoped (Rib::Kind::Normal /* FIXME: Is that valid? */, // Namespace::Labels, // let.get_node_id (), [] () {}); } void Late::visit (AST::IdentifierPattern &identifier) { // do we insert in labels or in values // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? new_label (identifier.get_ident (), identifier.get_node_id ()); } void Late::visit (AST::IdentifierExpr &expr) { // TODO: same thing as visit(PathInExpression) here? tl::optional resolved = tl::nullopt; auto label = ctx.labels.get (expr.get_ident ()); auto value = ctx.values.get (expr.get_ident ()); if (label) resolved = label; else if (value) resolved = value; // TODO: else emit error? ctx.map_usage (expr.get_node_id (), *resolved); // in the old resolver, resolutions are kept in the resolver, not the mappings // :/ how do we deal with that? // ctx.mappings.insert_resolved_name(expr, resolved); // For empty types, do we perform a lookup in ctx.types or should the // toplevel instead insert a name in ctx.values? (like it currently does) } void Late::visit (AST::PathInExpression &expr) { // TODO: How do we have a nice error with `can't capture dynamic environment // in a function item` error here? // do we emit it in `get`? auto label = ctx.labels.resolve_path (expr.get_segments ()); auto value = ctx.values.resolve_path (expr.get_segments ()); } void Late::visit (AST::TypePath &type) { // should we add type path resolution in `ForeverStack` directly? Since it's // quite more complicated. // maybe we can overload `resolve_path` to only do // typepath-like path resolution? that sounds good auto resolved = ctx.types.get (type.get_segments ().back ()->as_string ()); ctx.map_usage (type.get_node_id (), *resolved); } } // namespace Resolver2_0 } // namespace Rust