aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2024-01-11 14:45:15 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2024-01-15 08:52:39 +0200
commit05ee8c20d83c2f108aa71a65e19b7adff8ff9aa0 (patch)
tree34f54b78150895a1bf1c93214a0b5cfc8203dd8f
parent1d925696ac7eb8d7adb4d70b3f5afb010d745931 (diff)
Fail with unable to import rather than unknown target type
-rw-r--r--libbuild2/file.cxx69
-rw-r--r--libbuild2/file.hxx11
-rw-r--r--libbuild2/functions-name.cxx34
-rw-r--r--libbuild2/parser.cxx21
-rw-r--r--libbuild2/scope.cxx12
-rw-r--r--libbuild2/scope.hxx12
-rw-r--r--libbuild2/scope.ixx6
7 files changed, 140 insertions, 25 deletions
diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx
index e62e607..81a9dac 100644
--- a/libbuild2/file.cxx
+++ b/libbuild2/file.cxx
@@ -2063,16 +2063,13 @@ namespace build2
&t);
}
- // Suggest appropriate ways to import the specified target (as type and
- // name) from the specified project.
- //
- static void
+ void
import_suggest (const diag_record& dr,
const project_name& pn,
const target_type* tt,
const string& tn,
bool rule_hint,
- const char* qual = nullptr)
+ const char* qual)
{
string pv (pn.variable ());
@@ -2899,6 +2896,11 @@ namespace build2
static names
import2_buildfile (context&, names&&, bool, const location&);
+ static const target*
+ import2 (context&, const scope&, names&,
+ const string&, bool, const optional<string>&, bool,
+ const location&);
+
pair<names, import_kind>
import (scope& base,
name tgt,
@@ -2971,7 +2973,7 @@ namespace build2
// fallback case.
//
if (const target* t = import2 (ctx,
- base.find_prerequisite_key (ns, loc),
+ base, ns,
*ph2,
opt && !r.second /* optional */,
nullopt /* metadata */,
@@ -3168,6 +3170,8 @@ namespace build2
return *t;
}
+ // NOTE: see similar code in import2() below if changing anything here.
+
if (opt || exist)
return nullptr;
@@ -3185,6 +3189,57 @@ namespace build2
dr << endf;
}
+ // As above but with scope/ns instead of pk. This version deals with the
+ // unknown target type case.
+ //
+ static const target*
+ import2 (context& ctx,
+ const scope& base, names& ns,
+ const string& hint,
+ bool opt,
+ const optional<string>& meta,
+ bool exist,
+ const location& loc)
+ {
+ // If we have a rule hint, then it's natural to expect this target type is
+ // known to the importing project. Ditto for project-less import.
+ //
+ const target_type* tt (nullptr);
+ if (hint.empty ())
+ {
+ size_t n;
+ if ((n = ns.size ()) != 0 && n == (ns[0].pair ? 2 : 1))
+ {
+ const name& n (ns.front ());
+
+ if (n.typed () && !n.proj->empty ())
+ {
+ tt = base.find_target_type (n.type);
+
+ if (tt == nullptr)
+ {
+ // A subset of code in the above version of import2().
+ //
+ if (opt || exist)
+ return nullptr;
+
+ diag_record dr;
+ dr << fail (loc) << "unable to import target " << ns;
+ import_suggest (dr, *n.proj, nullptr, string (), meta.has_value ());
+ }
+ }
+ }
+ }
+
+ return import2 (ctx,
+ base.find_prerequisite_key (ns, loc, tt),
+ hint,
+ opt,
+ meta,
+ exist,
+ loc);
+ }
+
static names
import2_buildfile (context&, names&& ns, bool opt, const location& loc)
{
@@ -3323,7 +3378,7 @@ namespace build2
// fallback case.
//
pt = import2 (ctx,
- base.find_prerequisite_key (ns, loc),
+ base, ns,
*ph2,
opt && !r.second,
meta,
diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx
index 6c5097d..68c284b 100644
--- a/libbuild2/file.hxx
+++ b/libbuild2/file.hxx
@@ -518,6 +518,17 @@ namespace build2
bool metadata,
const location&);
+ // Suggest appropriate ways to import the specified target (as type and
+ // name) from the specified project.
+ //
+ void
+ import_suggest (const diag_record&,
+ const project_name&,
+ const target_type*,
+ const string& name,
+ bool rule_hint,
+ const char* qual = nullptr);
+
// Create a build system project in the specified directory.
//
LIBBUILD2_SYMEXPORT void
diff --git a/libbuild2/functions-name.cxx b/libbuild2/functions-name.cxx
index fcb492f..456f85b 100644
--- a/libbuild2/functions-name.cxx
+++ b/libbuild2/functions-name.cxx
@@ -97,7 +97,18 @@ namespace build2
const target_type* ntt (to_target_type (s, n, o).first);
if (ntt == nullptr)
+ {
+ // If this is an imported target and the target type is unknown, then
+ // it cannot possibly match one of the known types. We handle it like
+ // this instead of failing because the later failure (e.g., as a
+ // result of this target listed as prerequisite) will have more
+ // accurate diagnostics. See also filter() below.
+ //
+ if (n.proj)
+ return false;
+
fail << "unknown target type " << n.type << " in " << n;
+ }
return ntt->is_a (*tt);
}
@@ -142,13 +153,24 @@ namespace build2
const target_type* ntt (to_target_type (s, c, p ? *++i : name ()).first);
if (ntt == nullptr)
- fail << "unknown target type " << n.type << " in " << n;
+ {
+ // If this is an imported target and the target type is unknown, then
+ // it cannot possibly match one of the known types. We handle it like
+ // this instead of failing because the later failure (e.g., as a
+ // result of this target listed as prerequisite) will have more
+ // accurate diagnostics. See also is_a() above.
+ //
+ if (!n.proj)
+ fail << "unknown target type " << n.type << " in " << n;
+ }
- if ((find_if (tts.begin (), tts.end (),
- [ntt] (const target_type* tt)
- {
- return ntt->is_a (*tt);
- }) != tts.end ()) != out)
+ if (ntt != nullptr
+ ? (find_if (tts.begin (), tts.end (),
+ [ntt] (const target_type* tt)
+ {
+ return ntt->is_a (*tt);
+ }) != tts.end ()) != out
+ : out)
{
r.push_back (move (n));
if (p)
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index 71465f0..baf404a 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -2778,9 +2778,24 @@ namespace build2
optional<string>& e (rp.second);
if (t == nullptr)
- fail (ploc) << "unknown target type " << n.type <<
- info << "perhaps the module that defines this target type is "
- << "not loaded by project " << *scope_->root_scope ();
+ {
+ if (n.proj)
+ {
+ // If the target type is unknown then no phase 2 import (like
+ // rule-specific search) can possibly succeed so we can fail now and
+ // with a more accurate reason. See import2(names) for background.
+ //
+ diag_record dr;
+ dr << fail (ploc) << "unable to import target " << n;
+ import_suggest (dr, *n.proj, nullptr, string (), false);
+ }
+ else
+ {
+ fail (ploc) << "unknown target type " << n.type <<
+ info << "perhaps the module that defines this target type is "
+ << "not loaded by project " << *scope_->root_scope ();
+ }
+ }
if (t->factory == nullptr)
fail (ploc) << "abstract target type " << t->name << "{}";
diff --git a/libbuild2/scope.cxx b/libbuild2/scope.cxx
index c1c5ed7..4c9f301 100644
--- a/libbuild2/scope.cxx
+++ b/libbuild2/scope.cxx
@@ -893,9 +893,11 @@ namespace build2
}
pair<const target_type&, optional<string>> scope::
- find_prerequisite_type (name& n, name& o, const location& loc) const
+ find_prerequisite_type (name& n, name& o,
+ const location& loc,
+ const target_type* tt) const
{
- auto r (find_target_type (n, loc));
+ auto r (find_target_type (n, loc, tt));
if (r.first == nullptr)
fail (loc) << "unknown target type " << n.type << " in " << n;
@@ -919,14 +921,16 @@ namespace build2
}
prerequisite_key scope::
- find_prerequisite_key (names& ns, const location& loc) const
+ find_prerequisite_key (names& ns,
+ const location& loc,
+ const target_type* tt) const
{
if (size_t n = ns.size ())
{
if (n == (ns[0].pair ? 2 : 1))
{
name dummy;
- return find_prerequisite_key (ns[0], n == 1 ? dummy : ns[1], loc);
+ return find_prerequisite_key (ns[0], n == 1 ? dummy : ns[1], loc, tt);
}
}
diff --git a/libbuild2/scope.hxx b/libbuild2/scope.hxx
index 50347b2..3f6b0af 100644
--- a/libbuild2/scope.hxx
+++ b/libbuild2/scope.hxx
@@ -376,15 +376,21 @@ namespace build2
// directories.
//
pair<const target_type&, optional<string>>
- find_prerequisite_type (name&, name&, const location&) const;
+ find_prerequisite_type (name&, name&,
+ const location&,
+ const target_type* tt = nullptr) const;
// As above, but return a prerequisite key.
//
prerequisite_key
- find_prerequisite_key (name&, name&, const location&) const;
+ find_prerequisite_key (name&, name&,
+ const location&,
+ const target_type* = nullptr) const;
prerequisite_key
- find_prerequisite_key (names&, const location&) const;
+ find_prerequisite_key (names&,
+ const location&,
+ const target_type* = nullptr) const;
// Dynamically derive a new target type from an existing one. Return the
// reference to the target type and an indicator of whether it was
diff --git a/libbuild2/scope.ixx b/libbuild2/scope.ixx
index 5d76a7f..4543f2c 100644
--- a/libbuild2/scope.ixx
+++ b/libbuild2/scope.ixx
@@ -158,9 +158,11 @@ namespace build2
}
inline prerequisite_key scope::
- find_prerequisite_key (name& n, name& o, const location& loc) const
+ find_prerequisite_key (name& n, name& o,
+ const location& loc,
+ const target_type* tt) const
{
- auto p (find_prerequisite_type (n, o, loc));
+ auto p (find_prerequisite_type (n, o, loc, tt));
return prerequisite_key {
n.proj,
{