1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-10 20:46:01 +01:00

Merge remote-tracking branch 'origin/master' into coerce-string

This commit is contained in:
Guillaume Maudoux 2022-03-18 01:25:55 +01:00
commit ca5c3e86ab
89 changed files with 1857 additions and 699 deletions

View file

@ -63,9 +63,15 @@ static char * dupString(const char * s)
}
static char * dupStringWithLen(const char * s, size_t size)
// When there's no need to write to the string, we can optimize away empty
// string allocations.
// This function handles makeImmutableStringWithLen(null, 0) by returning the
// empty string.
static const char * makeImmutableStringWithLen(const char * s, size_t size)
{
char * t;
if (size == 0)
return "";
#if HAVE_BOEHMGC
t = GC_STRNDUP(s, size);
#else
@ -75,6 +81,10 @@ static char * dupStringWithLen(const char * s, size_t size)
return t;
}
static inline const char * makeImmutableString(std::string_view s) {
return makeImmutableStringWithLen(s.data(), s.size());
}
RootValue allocRootValue(Value * v)
{
@ -439,8 +449,10 @@ EvalState::EvalState(
, regexCache(makeRegexCache())
#if HAVE_BOEHMGC
, valueAllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
, env1AllocCache(std::allocate_shared<void *>(traceable_allocator<void *>(), nullptr))
#else
, valueAllocCache(std::make_shared<void *>(nullptr))
, env1AllocCache(std::make_shared<void *>(nullptr))
#endif
, baseEnv(allocEnv(128))
, staticBaseEnv(false, 0)
@ -702,9 +714,18 @@ LocalNoInlineNoReturn(void throwTypeErrorWithTrace(const Pos & pos, const char *
}).addTrace(p2, s3);
}
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const Suggestions & suggestions, const char * s, const std::string & s2))
{
throw EvalError(ErrorInfo {
.msg = hintfmt(s, s2),
.errPos = pos,
.suggestions = suggestions,
});
}
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const std::string & s2))
{
throw EvalError({
throw EvalError(ErrorInfo {
.msg = hintfmt(s, s2),
.errPos = pos
});
@ -727,6 +748,37 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const
});
}
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s))
{
throw TypeError({
.msg = hintfmt(s),
.errPos = pos
});
}
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2))
{
throw TypeError({
.msg = hintfmt(s, fun.showNamePos(), s2),
.errPos = pos
});
}
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const Suggestions & suggestions, const char * s, const ExprLambda & fun, const Symbol & s2))
{
throw TypeError(ErrorInfo {
.msg = hintfmt(s, fun.showNamePos(), s2),
.errPos = pos,
.suggestions = suggestions,
});
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v))
{
throw TypeError(s, showType(v));
}
LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const std::string & s1))
{
throw AssertionError({
@ -764,7 +816,7 @@ LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, con
void Value::mkString(std::string_view s)
{
mkString(dupStringWithLen(s.data(), s.size()));
mkString(makeImmutableString(s));
}
@ -795,7 +847,7 @@ void Value::mkStringMove(const char * s, const PathSet & context)
void Value::mkPath(std::string_view s)
{
mkPath(dupStringWithLen(s.data(), s.size()));
mkPath(makeImmutableString(s));
}
@ -825,42 +877,6 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval)
}
Value * EvalState::allocValue()
{
/* We use the boehm batch allocator to speed up allocations of Values (of which there are many).
GC_malloc_many returns a linked list of objects of the given size, where the first word
of each object is also the pointer to the next object in the list. This also means that we
have to explicitly clear the first word of every object we take. */
if (!*valueAllocCache) {
*valueAllocCache = GC_malloc_many(sizeof(Value));
if (!*valueAllocCache) throw std::bad_alloc();
}
/* GC_NEXT is a convenience macro for accessing the first word of an object.
Take the first list item, advance the list to the next item, and clear the next pointer. */
void * p = *valueAllocCache;
GC_PTR_STORE_AND_DIRTY(&*valueAllocCache, GC_NEXT(p));
GC_NEXT(p) = nullptr;
nrValues++;
auto v = (Value *) p;
return v;
}
Env & EvalState::allocEnv(size_t size)
{
nrEnvs++;
nrValuesInEnvs += size;
Env * env = (Env *) allocBytes(sizeof(Env) + size * sizeof(Value *));
env->type = Env::Plain;
/* We assume that env->values has been cleared by the allocator; maybeThunk() and lookupVar fromWith expect this. */
return *env;
}
void EvalState::mkList(Value & v, size_t size)
{
v.mkList(size);
@ -1230,8 +1246,15 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
}
} else {
state.forceAttrs(*vAttrs, pos, "While selecting an attribute");
if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end())
throwEvalError(pos, "attribute '%1%' missing", name);
if ((j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) {
std::set<std::string> allAttrNames;
for (auto & attr : *vAttrs->attrs)
allAttrNames.insert(attr.name);
throwEvalError(
pos,
Suggestions::bestMatches(allAttrNames, name),
"attribute '%1%' missing", name);
}
}
vAttrs = j->value;
pos2 = j->pos;
@ -1360,7 +1383,11 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
user. */
for (auto & i : *args[0]->attrs)
if (!lambda.formals->has(i.name)) {
std::set<std::string> formalNames;
for (auto & formal : lambda.formals->formals)
formalNames.insert(formal.name);
throwTypeErrorWithTrace(lambda.pos,
Suggestions::bestMatches(formalNames, i.name),
"Function '%1%' called with unexpected argument '%2%'", prettyLambdaName(lambda), i.name,
pos, "from call site");
}